// 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:dds/src/dap/isolate_manager.dart'; import 'package:test/test.dart'; import 'package:vm_service/vm_service.dart'; import 'mocks.dart'; main() { group('IsolateManager', () { late MockDartCliDebugAdapter adapter; late IsolateManager isolateManager; setUp(() async { adapter = MockDartCliDebugAdapter(); isolateManager = adapter.isolateManager; isolateManager.debug = true; isolateManager.debugSdkLibraries = false; isolateManager.debugExternalPackageLibraries = true; await isolateManager.registerIsolate( adapter.mockService.isolate1, EventKind.kIsolateStart, ); await isolateManager.registerIsolate( adapter.mockService.isolate2, EventKind.kIsolateStart, ); }); test('sends only changes to SDK libraries debuggable flag', () async { // Default is false, so should not send anything. isolateManager.debugSdkLibraries = false; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, isNot( contains(startsWith('setLibraryDebuggable(isolate1, libSdk,')), ), ); // Changing to non-default should send a request. isolateManager.debugSdkLibraries = true; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, contains('setLibraryDebuggable(isolate1, libSdk, true)'), ); // Setting back to default should now send. isolateManager.debugSdkLibraries = false; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, contains('setLibraryDebuggable(isolate1, libSdk, false)'), ); }); test('sends only changes to external package libraries debuggable flag', () async { // Default is true, so should not send anything. isolateManager.debugExternalPackageLibraries = true; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, isNot( contains( startsWith('setLibraryDebuggable(isolate1, libPkgExternal,')), ), ); // Changing to non-default should send a request. isolateManager.debugExternalPackageLibraries = false; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, contains('setLibraryDebuggable(isolate1, libPkgExternal, false)'), ); // Setting back to default should now send. isolateManager.debugExternalPackageLibraries = true; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, contains('setLibraryDebuggable(isolate1, libPkgExternal, true)'), ); }); /// Local packages are always debuggable, in the VM and because we have no /// settings. No changes should ever cause requests for them. test('never sends values for local package libraries debuggable flag', () async { isolateManager.debugSdkLibraries = true; isolateManager.debugExternalPackageLibraries = true; await isolateManager.applyDebugOptions(); isolateManager.debugSdkLibraries = false; isolateManager.debugExternalPackageLibraries = false; await isolateManager.applyDebugOptions(); expect( adapter.mockService.requests, isNot( contains(startsWith('setLibraryDebuggable(isolate1, libPkgLocal,')), ), ); }); test('clears thread data on resume', () async { final thread1 = isolateManager.threads[0]; final thread2 = isolateManager.threads[1]; // Store some data in both threads. final ref1 = thread1.storeData("test1"); final ref2 = thread2.storeData("test2"); // Resume thread1 thread1.paused = true; // Fake pause to allow resume. await isolateManager.resumeThread(thread1.threadId); // Ensure thread1 had data cleared, but thread2 did not. expect(isolateManager.getStoredData(ref1), isNull); expect(isolateManager.getStoredData(ref2), isNotNull); }); test('uses uri converter to convert resolved uri', () async { String? receivedUri; adapter.setUriConverter((uri) { receivedUri = uri; return '/returned/file/path.dart'; }); adapter.mockService.lookupResolvedPackageUrisResponse = UriList(uris: ['scheme://file/path.dart']); final thread = isolateManager.threads[0]; final resolved = await thread.resolveUriToPath(Uri.parse('package:pkg/path.dart')); expect(adapter.mockService.receivedLookupResolvedPackageUris, ['package:pkg/path.dart']); expect(receivedUri, 'scheme://file/path.dart'); expect(resolved, Uri.file('/returned/file/path.dart')); }); test('sends resume after kPausePostRequest', () async { // Trigger initial startup. await adapter.isolateManager.handleEvent(Event( isolate: adapter.mockService.isolate1, kind: EventKind.kIsolateRunnable)); isolateManager.threads[0].startupHandled = true; // Clear any previously called methods. adapter.mockService.calledMethods.clear(); // Now simulate a hot reload causing the isolate to pause again. await adapter.isolateManager.handleEvent(Event( isolate: adapter.mockService.isolate1, kind: EventKind.kPausePostRequest)); // Ensure we called readyToResume. expect(adapter.mockService.calledMethods.map((cm) => cm.method), contains('readyToResume')); // Expect it was resumed. }); }); }