| // 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 'dart:async'; |
| |
| import 'package:test/test.dart'; |
| import 'package:vm_service/vm_service.dart'; |
| |
| import 'common/service_test_common.dart'; |
| import 'common/test_helper.dart'; |
| |
| int counter = 0; |
| const LINE_A = 20; |
| const LINE_B = LINE_A + 1; |
| const LINE_C = LINE_A - 2; |
| |
| void periodicTask(_) { |
| counter++; |
| counter++; // Line 19. We set our breakpoint here. |
| counter++; |
| if (counter % 300 == 0) { |
| print('counter = $counter'); |
| } |
| } |
| |
| void startTimer() { |
| Timer.periodic(const Duration(milliseconds: 10), periodicTask); |
| } |
| |
| Future<void> waitForEvent(VmService service, String eventKind) { |
| final completer = Completer<void>(); |
| late final StreamSubscription<Event> subscription; |
| subscription = service.onDebugEvent.listen((Event event) { |
| if (event.kind == eventKind) { |
| subscription.cancel(); |
| completer.complete(); |
| } |
| }); |
| return completer.future; |
| } |
| |
| final tests = <IsolateTest>[ |
| // Initialize stream. |
| (VmService service, IsolateRef isolateRef) async { |
| await service.streamListen(EventStreams.kDebug); |
| }, |
| // Pause |
| (VmService service, IsolateRef isolateRef) async { |
| final isolateId = isolateRef.id!; |
| final event = waitForEvent(service, EventKind.kPauseInterrupted); |
| await service.pause(isolateId); |
| await event; |
| }, |
| |
| // Resume |
| resumeIsolate, |
| |
| // Add breakpoint |
| (VmService service, IsolateRef isolateRef) async { |
| final isolateId = isolateRef.id!; |
| var isolate = await service.getIsolate(isolateId); |
| final rootLib = |
| await service.getObject(isolateId, isolate.rootLib!.id!) as Library; |
| final scriptId = rootLib.scripts![0].id!; |
| final script = await service.getObject(isolateId, scriptId) as Script; |
| |
| final event = waitForEvent(service, EventKind.kPauseBreakpoint); |
| |
| // Add the breakpoint. |
| final bpt = await service.addBreakpoint(isolateId, scriptId, LINE_A); |
| expect(bpt.location!.script!.id, scriptId); |
| expect(script.getLineNumberFromTokenPos(bpt.location!.tokenPos), LINE_A); |
| |
| isolate = await service.getIsolate(isolateId); |
| expect(isolate.breakpoints!.length, 1); |
| |
| await event; // Wait for breakpoint events. |
| }, |
| |
| // We are at the breakpoint on LINE_A. |
| stoppedAtLine(LINE_A), |
| |
| // Stepping |
| (VmService service, IsolateRef isolateRef) async { |
| final event = waitForEvent(service, EventKind.kPauseBreakpoint); |
| await service.resume(isolateRef.id!, step: StepOption.kOver); |
| await event; // Wait for breakpoint events. |
| }, |
| |
| // We are now at line LINE_B. |
| stoppedAtLine(LINE_B), |
| |
| // Remove breakpoint |
| (VmService service, IsolateRef isolateRef) async { |
| final isolateId = isolateRef.id!; |
| var isolate = await service.getIsolate(isolateId); |
| |
| // Set up a listener to wait for breakpoint events. |
| final event = waitForEvent(service, EventKind.kBreakpointRemoved); |
| |
| expect(isolate.breakpoints!.length, 1); |
| final bpt = isolate.breakpoints!.first; |
| await service.removeBreakpoint(isolateId, bpt.id!); |
| await event; |
| |
| isolate = await service.getIsolate(isolateId); |
| expect(isolate.breakpoints!.length, 0); |
| }, |
| |
| // Resume |
| resumeIsolate, |
| |
| // Add breakpoint at function entry |
| (VmService service, IsolateRef isolateRef) async { |
| // Set up a listener to wait for breakpoint events. |
| final event = waitForEvent(service, EventKind.kPauseBreakpoint); |
| |
| final isolateId = isolateRef.id!; |
| var isolate = await service.getIsolate(isolateId); |
| final rootLib = |
| await service.getObject(isolateId, isolate.rootLib!.id!) as Library; |
| |
| // Find a specific function. |
| final function = rootLib.functions!.firstWhere( |
| (f) => f.name == 'periodicTask', |
| ); |
| |
| // Add the breakpoint at function entry |
| final bpt = await service.addBreakpointAtEntry(isolateId, function.id!); |
| |
| final script = |
| await service.getObject(isolateId, bpt.location!.script!.id!) as Script; |
| expect(script.uri, endsWith('debugging_test.dart')); |
| expect(script.getLineNumberFromTokenPos(bpt.location!.tokenPos), LINE_C); |
| |
| isolate = await service.getIsolate(isolateId); |
| expect(isolate.breakpoints!.length, 1); |
| |
| await event; // Wait for breakpoint events. |
| }, |
| |
| // We are now at line LINE_C, the entrypoint for periodicTask. |
| stoppedAtLine(LINE_C), |
| ]; |
| |
| void main(List<String> args) => runIsolateTests( |
| args, |
| tests, |
| 'debugging_test.dart', |
| testeeBefore: startTimer, |
| ); |