| // 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:developer'; |
| |
| import 'package:test/test.dart'; |
| import 'package:vm_service/vm_service.dart'; |
| |
| import 'common/service_test_common.dart'; |
| import 'common/test_helper.dart'; |
| |
| Future<void> bar(int depth) async { |
| if (depth == 21) { |
| debugger(); |
| return; |
| } |
| await foo(depth + 1); |
| } |
| |
| Future<void> foo(int depth) async { |
| if (depth == 10) { |
| // Yield once to force the rest to run async. |
| // ignore: await_only_futures |
| await 0; |
| } |
| await bar(depth + 1); |
| } |
| |
| Future<void> testMain() async { |
| await foo(0); |
| } |
| |
| void verifyStack(List<Frame> frames, List<String> expectedNames) { |
| for (int i = 0; i < frames.length && i < expectedNames.length; ++i) { |
| expect(frames[i].function!.name, expectedNames[i]); |
| } |
| } |
| |
| final tests = <IsolateTest>[ |
| hasStoppedAtBreakpoint, |
| // Get stack |
| (VmService service, IsolateRef isolateRef) async { |
| final isolateId = isolateRef.id!; |
| var stack = await service.getStack(isolateId); |
| |
| // Sanity check. |
| var frames = stack.frames!; |
| var asyncFrames = stack.asyncCausalFrames!; |
| expect(frames.length, greaterThanOrEqualTo(12)); |
| expect(asyncFrames.length, greaterThan(frames.length)); |
| expect(stack.truncated, false); |
| verifyStack(frames, [ |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| ]); |
| |
| final fullStackLength = frames.length; |
| |
| // Try a limit > actual stack depth and expect to get the full stack with |
| // truncated async stacks. |
| stack = await service.getStack(isolateId, limit: fullStackLength + 1); |
| frames = stack.frames!; |
| asyncFrames = stack.asyncCausalFrames!; |
| |
| expect(frames.length, fullStackLength); |
| expect(asyncFrames.length, fullStackLength + 1); |
| expect(stack.truncated, true); |
| verifyStack(frames, [ |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| ]); |
| |
| // Try a limit < actual stack depth and expect to get a stack of depth |
| // 'limit'. |
| stack = await service.getStack(isolateId, limit: 10); |
| frames = stack.frames!; |
| asyncFrames = stack.asyncCausalFrames!; |
| |
| expect(frames.length, 10); |
| expect(asyncFrames.length, 10); |
| expect(stack.truncated, true); |
| verifyStack(frames, [ |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| 'bar', |
| 'foo', |
| ]); |
| }, |
| // Invalid limit |
| (VmService service, IsolateRef isolateRef) async { |
| bool caughtException = false; |
| try { |
| await service.getStack(isolateRef.id!, limit: -1); |
| fail('Invalid parameter of -1 successful'); |
| } on RPCError { |
| // Expected. |
| caughtException = true; |
| } |
| expect(caughtException, true); |
| } |
| ]; |
| |
| void main([args = const <String>[]]) => runIsolateTests( |
| args, |
| tests, |
| 'get_stack_limit_rpc_test.dart', |
| testeeConcurrent: testMain, |
| ); |