// Copyright (c) 2022, 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. @TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:test/test.dart'; import 'package:test_common/logging.dart'; import 'package:test_common/test_sdk_configuration.dart'; import 'package:vm_service/vm_service.dart'; import 'package:vm_service_interface/vm_service_interface.dart'; import 'fixtures/context.dart'; import 'fixtures/project.dart'; import 'fixtures/utilities.dart'; void testAll({ required TestSdkConfigurationProvider provider, CompilationMode compilationMode = CompilationMode.buildDaemon, IndexBaseMode indexBaseMode = IndexBaseMode.noBase, bool useDebuggerModuleNames = false, bool debug = false, }) { if (compilationMode == CompilationMode.buildDaemon && indexBaseMode == IndexBaseMode.base) { throw StateError( 'build daemon scenario does not support non-empty base in index file', ); } final testCircular1 = TestProject.testCircular1; final testCircular2 = TestProject.testCircular2(baseMode: indexBaseMode); final context = TestContext(testCircular2, provider); Future onBreakPoint( String isolate, ScriptRef script, String breakPointId, Future Function() body, ) async { Breakpoint? bp; try { final line = await context.findBreakpointLine( breakPointId, isolate, script, ); bp = await context.service.addBreakpointWithScriptUri( isolate, script.uri!, line, ); await body(); } finally { // Remove breakpoint so it doesn't impact other tests or retries. if (bp != null) { await context.service.removeBreakpoint(isolate, bp.id!); } } } group('shared context with evaluation', () { setUpAll(() async { setCurrentLogWriter(debug: debug); await context.setUp( testSettings: TestSettings( compilationMode: compilationMode, enableExpressionEvaluation: true, useDebuggerModuleNames: useDebuggerModuleNames, verboseCompiler: debug, ), ); }); tearDownAll(() async { await context.tearDown(); }); setUp(() => setCurrentLogWriter(debug: debug)); group('evaluateInFrame', () { late VmServiceInterface service; VM vm; late Isolate isolate; late String isolateId; ScriptList scripts; late ScriptRef test1LibraryScript; late ScriptRef test2LibraryScript; late Stream stream; setUp(() async { setCurrentLogWriter(debug: debug); service = context.service; vm = await service.getVM(); isolate = await service.getIsolate(vm.isolates!.first.id!); isolateId = isolate.id!; scripts = await service.getScripts(isolateId); await service.streamListen('Debug'); stream = service.onEvent('Debug'); final test1 = testCircular1.packageName; final test2 = testCircular2.packageName; test1LibraryScript = scripts.scripts!.firstWhere( (each) => each.uri!.contains('package:$test1/library1.dart'), ); test2LibraryScript = scripts.scripts!.firstWhere( (each) => each.uri!.contains('package:$test2/library2.dart'), ); }); tearDown(() async { await service.resume(isolateId); }); test('evaluate expression in _test_circular1/library', () async { await onBreakPoint( isolateId, test1LibraryScript, 'Concatenate', () async { final event = await stream.firstWhere( (event) => event.kind == EventKind.kPauseBreakpoint, ); final result = await context.service.evaluateInFrame( isolateId, event.topFrame!.index!, 'a', ); expect( result, isA().having( (instance) => instance.valueAsString, 'valueAsString', 'a', ), ); }, ); }); test('evaluate expression in _test_circular2/library', () async { await onBreakPoint( isolateId, test2LibraryScript, 'testCircularDependencies', () async { final event = await stream.firstWhere( (event) => event.kind == EventKind.kPauseBreakpoint, ); final result = await context.service.evaluateInFrame( isolateId, event.topFrame!.index!, 'true', ); expect( result, isA().having( (instance) => instance.valueAsString, 'valueAsString', 'true', ), ); }, ); }); }); }); }