| // Copyright (c) 2015, 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. |
| // VMOptions=--error_on_bad_type --error_on_bad_override --verbose_debug --trace_service |
| |
| import 'dart:async'; |
| import 'dart:developer'; |
| |
| import 'test_helper.dart'; |
| import 'service_test_common.dart'; |
| |
| import 'package:observatory/service_io.dart'; |
| import 'package:unittest/unittest.dart'; |
| |
| const int LINE_A = 24; |
| const int LINE_B = 26; |
| const int LINE_C = 28; |
| const int LINE_D = 29; |
| |
| // This tests the low level synthetic breakpoint added / paused / removed |
| // machinery triggered by the step OverAwait command. |
| asyncWithoutAwait() async { |
| debugger(); |
| print('a'); // LINE_A |
| await new Future.delayed(new Duration(seconds: 2)); |
| print('b'); // LINE_B |
| debugger(); // LINE_C |
| debugger(); // LINE_D |
| } |
| |
| testMain() { |
| asyncWithoutAwait(); |
| } |
| |
| Breakpoint syntheticBreakpoint; |
| |
| Future<Isolate> testLowLevelAwaitOver( |
| Isolate isolate) { |
| assert(isolate.pauseEvent.atAsyncSuspension); |
| |
| int state = 0; |
| bool firstResume = true; |
| handleBreakpointAdded(ServiceEvent event) { |
| expect(syntheticBreakpoint, isNull); |
| expect(state, 0); |
| if (!event.breakpoint.isSyntheticAsyncContinuation) { |
| // Not a synthetic async breakpoint. |
| return; |
| } |
| if (event.owner != isolate) { |
| // Wrong isolate. |
| return; |
| } |
| syntheticBreakpoint = event.breakpoint; |
| print('!!!! Synthetic async breakpoint added ${syntheticBreakpoint}'); |
| state = 1; |
| } |
| |
| handleResume(ServiceEvent event) { |
| if (firstResume) { |
| expect(state, 1); |
| if (event.owner != isolate) { |
| // Wrong isolate. |
| return; |
| } |
| print('!!!! Got first resume.'); |
| state = 2; |
| firstResume = false; |
| } else { |
| expect(state, 3); |
| if (event.owner != isolate) { |
| // Wrong isolate. |
| return; |
| } |
| print('!!!! Got second resume.'); |
| state = 4; |
| } |
| |
| } |
| |
| handlePauseBreakpoint(ServiceEvent event) { |
| expect(syntheticBreakpoint, isNotNull); |
| expect(state, 2); |
| if (!event.breakpoint.isSyntheticAsyncContinuation) { |
| // Not a synthetic async breakpoint. |
| return; |
| } |
| if (event.owner != isolate) { |
| // Wrong isolate. |
| return; |
| } |
| expect(event.breakpoint, equals(syntheticBreakpoint)); |
| print('!!!! Paused at synthetic async breakpoint ${syntheticBreakpoint}'); |
| state = 3; |
| } |
| |
| handleBreakpointRemoved(ServiceEvent event) { |
| expect(syntheticBreakpoint, isNotNull); |
| expect(state, 4); |
| if (!event.breakpoint.isSyntheticAsyncContinuation) { |
| // Not a synthetic async breakpoint. |
| return; |
| } |
| if (event.owner != isolate) { |
| // Wrong isolate. |
| return; |
| } |
| expect(event.breakpoint, equals(syntheticBreakpoint)); |
| print('!!!! Synthetic async breakpoint removed ${syntheticBreakpoint}'); |
| state = 5; |
| syntheticBreakpoint = null; |
| } |
| |
| // Set up a listener to wait for debugger events. |
| Completer completer = new Completer(); |
| isolate.vm.getEventStream(VM.kDebugStream).then((stream) { |
| var subscription; |
| subscription = stream.listen((ServiceEvent event) async { |
| if (event.kind == ServiceEvent.kBreakpointAdded) { |
| handleBreakpointAdded(event); |
| expect(state, 1); |
| } else if (event.kind == ServiceEvent.kResume) { |
| if (firstResume) { |
| handleResume(event); |
| expect(state, 2); |
| } else { |
| handleResume(event); |
| expect(state, 4); |
| } |
| } else if (event.kind == ServiceEvent.kPauseBreakpoint) { |
| handlePauseBreakpoint(event); |
| expect(state, 3); |
| // Check that we are paused after the await statement. |
| await (stoppedAtLine(LINE_B)(isolate)); |
| // Resume the isolate so that we trigger the breakpoint removal. |
| print('!!!! Triggering synthetic breakpoint removal.'); |
| isolate.resume(); |
| } else if (event.kind == ServiceEvent.kBreakpointRemoved) { |
| handleBreakpointRemoved(event); |
| expect(state, 5); |
| subscription.cancel(); |
| if (completer != null) { |
| // Reload to update isolate.pauseEvent. |
| completer.complete(isolate.reload()); |
| completer = null; |
| } |
| } |
| }); |
| }); |
| |
| isolate.stepOverAsyncSuspension(); |
| |
| return completer.future; // Will complete when breakpoint added. |
| } |
| |
| |
| var tests = [ |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_A), |
| stepOver, |
| stepOver, |
| stepOver, |
| (Isolate isolate) async { |
| expect(isolate.pauseEvent.atAsyncSuspension, isTrue); |
| expect(syntheticBreakpoint, isNull); |
| }, |
| testLowLevelAwaitOver, |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_C), |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_D), |
| resumeIsolate, |
| ]; |
| |
| main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain); |