// 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.

// ignore_for_file: library_private_types_in_public_api

library get_object_rpc_test;

import 'dart:collection';
import 'dart:convert' show base64Decode;
import 'dart:developer';
import 'dart:ffi';
import 'dart:typed_data';

import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';

import 'common/test_helper.dart';

abstract base mixin class _DummyAbstractBaseClass {
  void dummyFunction(int a, [bool b = false]);
}

base class _DummyClass extends _DummyAbstractBaseClass {
  // ignore: unused_field
  static var dummyVar = 11;
  final List<String> dummyList = List<String>.filled(20, '');
  // ignore: unused_field
  static var dummyVarWithInit = foo();
  late String dummyLateVarWithInit = 'bar';
  late String dummyLateVar;
  int get dummyVarGetter => dummyVar;
  set dummyVarSetter(int value) => dummyVar = value;
  @override
  void dummyFunction(int a, [bool b = false]) {}
  void dummyGenericFunction<K, V>(K a, {required V param}) {}
  static List foo() => List<String>.filled(20, '');
}

base class _DummyGenericSubClass<T> extends _DummyClass {}

final class _DummyFinalClass extends _DummyClass {}

sealed class _DummySealedClass {}

interface class _DummyInterfaceClass extends _DummySealedClass {}

base mixin _DummyBaseMixin {
  void dummyMethod1() {}
}

mixin _DummyMixin {
  void dummyMethod2() {}
}

final class _DummyClassWithMixins with _DummyBaseMixin, _DummyMixin {}

void warmup() {
  // Increase the usage count of these methods.
  _DummyClass().dummyFunction(0);
  _DummyClass().dummyGenericFunction<Object, dynamic>(0, param: 0);
}

@pragma('vm:entry-point')
String getChattanooga() => 'Chattanooga';

@pragma('vm:entry-point')
List<int> getList() => [3, 2, 1];

@pragma('vm:entry-point')
Map<String, int> getMap() => {'x': 3, 'y': 4, 'z': 5};

@pragma('vm:entry-point')
Set<int> getSet() => {6, 7, 8};

@pragma('vm:entry-point')
Uint8List getUint8List() => Uint8List.fromList([3, 2, 1]);

@pragma('vm:entry-point')
Uint64List getUint64List() => Uint64List.fromList([3, 2, 1]);

@pragma('vm:entry-point')
(int, double, {int x, double y}) getRecord() => (1, x: 2, 3.0, y: 4.0);

@pragma('vm:entry-point')
_DummyClass getDummyClass() => _DummyClass();

@pragma('vm:entry-point')
_DummyFinalClass getDummyFinalClass() => _DummyFinalClass();

@pragma('vm:entry-point')
_DummyGenericSubClass<Object> getDummyGenericSubClass() =>
    _DummyGenericSubClass<Object>();

@pragma('vm:entry-point')
_DummyInterfaceClass getDummyInterfaceClass() => _DummyInterfaceClass();

@pragma('vm:entry-point')
_DummyClassWithMixins getDummyClassWithMixins() => _DummyClassWithMixins();

@pragma('vm:entry-point')
UserTag getUserTag() => UserTag('Test Tag');

@pragma('vm:entry-point')
Finalizer getFinalizer() {
  // Ensure at least one FinalizerEntry.
  finalizer.attach(
    nonGcedObject,
    _DummyClass(),
    detach: _DummyClass(),
  );
  return finalizer;
}

final finalizer = Finalizer((p0) {});
final nonGcedObject = _DummyClass();

@pragma('vm:entry-point')
NativeFinalizer getNativeFinalizer() {
  // Avoid adding entries here to avoid running on shutdown
  return nativeFinalizer;
}

final nativeFinalizer =
    NativeFinalizer(DynamicLibrary.process().lookup('free'));

var tests = <IsolateTest>[
  // null object.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'objects/null';
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kNull);
    expect(result.id, equals('objects/null'));
    expect(result.valueAsString, equals('null'));
    expect(result.classRef!.name, equals('Null'));
    expect(result.size, isPositive);
  },

  // bool object.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'objects/bool-true';
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kBool);
    expect(result.id, equals('objects/bool-true'));
    expect(result.valueAsString, equals('true'));
    expect(result.classRef!.name, equals('bool'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
  },

  // int object.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'objects/int-123';
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kInt);
    expect(result.json!['_vmType'], equals('Smi'));
    expect(result.id, equals('objects/int-123'));
    expect(result.valueAsString, equals('123'));
    expect(result.classRef!.name, equals('_Smi'));
    expect(result.size, isZero);
    expect(result.fields, isEmpty);
  },

  // A string
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart String.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getChattanooga',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kString);
    expect(result.json!['_vmType'], equals('String'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, equals('Chattanooga'));
    expect(result.classRef!.name, equals('_OneByteString'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(11));
    expect(result.offset, isNull);
    expect(result.count, isNull);
  },

  // String prefix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart String.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getChattanooga',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result =
        await service.getObject(isolateId, objectId, count: 4) as Instance;
    expect(result.kind, InstanceKind.kString);
    expect(result.json!['_vmType'], equals('String'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, equals('Chat'));
    expect(result.classRef!.name, equals('_OneByteString'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(11));
    expect(result.offset, isNull);
    expect(result.count, equals(4));
  },

  // String subrange.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart String.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getChattanooga',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 4,
      count: 6,
    ) as Instance;
    expect(result.kind, InstanceKind.kString);
    expect(result.json!['_vmType'], equals('String'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, equals('tanoog'));
    expect(result.classRef!.name, equals('_OneByteString'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(11));
    expect(result.offset, equals(4));
    expect(result.count, equals(6));
  },

  // String with wacky offset.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart String.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getChattanooga',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 100,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kString);
    expect(result.json!['_vmType'], equals('String'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, equals(''));
    expect(result.classRef!.name, equals('_OneByteString'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(11));
    expect(result.offset, equals(11));
    expect(result.count, equals(0));
  },

  // A built-in List.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getList', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kList);
    expect(result.json!['_vmType'], equals('GrowableObjectArray'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_GrowableList'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, isNull);
    final elements = result.elements!;
    expect(elements.length, equals(3));
    expect(elements[0] is InstanceRef, true);
    expect(elements[0].kind, InstanceKind.kInt);
    expect(elements[0].valueAsString, equals('3'));
    expect(elements[1] is InstanceRef, true);
    expect(elements[1].kind, InstanceKind.kInt);
    expect(elements[1].valueAsString, equals('2'));
    expect(elements[2] is InstanceRef, true);
    expect(elements[2].kind, InstanceKind.kInt);
    expect(elements[2].valueAsString, equals('1'));
  },

  // List prefix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getList', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result =
        await service.getObject(isolateId, objectId, count: 2) as Instance;
    expect(result.kind, InstanceKind.kList);
    expect(result.json!['_vmType'], equals('GrowableObjectArray'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_GrowableList'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, equals(2));
    final elements = result.elements!;
    expect(elements.length, equals(2));
    expect(elements[0] is InstanceRef, true);
    expect(elements[0].kind, InstanceKind.kInt);
    expect(elements[0].valueAsString, equals('3'));
    expect(elements[1] is InstanceRef, true);
    expect(elements[1].kind, InstanceKind.kInt);
    expect(elements[1].valueAsString, equals('2'));
  },

  // List suffix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getList', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 2,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kList);
    expect(result.json!['_vmType'], equals('GrowableObjectArray'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_GrowableList'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(2));
    expect(result.count, equals(1));
    final elements = result.elements!;
    expect(elements.length, equals(1));
    expect(elements[0] is InstanceRef, true);
    expect(elements[0].kind, InstanceKind.kInt);
    expect(elements[0].valueAsString, equals('1'));
  },

  // List with wacky offset.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getList', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 100,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kList);
    expect(result.json!['_vmType'], equals('GrowableObjectArray'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_GrowableList'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(3));
    expect(result.count, equals(0));
    expect(result.elements, isEmpty);
  },

  // A built-in Map.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart map.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getMap', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kMap);
    expect(result.json!['_vmType'], equals('Map'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Map'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, isNull);
    final associations = result.associations!;
    expect(associations.length, equals(3));
    expect(associations[0].key is InstanceRef, true);
    expect(associations[0].key.kind, InstanceKind.kString);
    expect(associations[0].key.valueAsString, equals('x'));
    expect(associations[0].value is InstanceRef, true);
    expect(associations[0].value.kind, InstanceKind.kInt);
    expect(associations[0].value.valueAsString, equals('3'));
    expect(associations[1].key is InstanceRef, true);
    expect(associations[1].key.kind, InstanceKind.kString);
    expect(associations[1].key.valueAsString, equals('y'));
    expect(associations[1].value is InstanceRef, true);
    expect(associations[1].value.kind, InstanceKind.kInt);
    expect(associations[1].value.valueAsString, equals('4'));
    expect(associations[2].key is InstanceRef, true);
    expect(associations[2].key.kind, InstanceKind.kString);
    expect(associations[2].key.valueAsString, equals('z'));
    expect(associations[2].value is InstanceRef, true);
    expect(associations[2].value.kind, InstanceKind.kInt);
    expect(associations[2].value.valueAsString, equals('5'));
  },

  // Map prefix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart map.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getMap', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result =
        await service.getObject(isolateId, objectId, count: 2) as Instance;
    expect(result.kind, InstanceKind.kMap);
    expect(result.json!['_vmType'], equals('Map'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Map'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, equals(2));
    final associations = result.associations!;
    expect(associations.length, equals(2));
    expect(associations[0].key is InstanceRef, true);
    expect(associations[0].key.kind, InstanceKind.kString);
    expect(associations[0].key.valueAsString, equals('x'));
    expect(associations[0].value is InstanceRef, true);
    expect(associations[0].value.kind, InstanceKind.kInt);
    expect(associations[0].value.valueAsString, equals('3'));
    expect(associations[1].key is InstanceRef, true);
    expect(associations[1].key.kind, InstanceKind.kString);
    expect(associations[1].key.valueAsString, equals('y'));
    expect(associations[1].value is InstanceRef, true);
    expect(associations[1].value.kind, InstanceKind.kInt);
    expect(associations[1].value.valueAsString, equals('4'));
  },

  // Map suffix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart map.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getMap', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 2,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kMap);
    expect(result.json!['_vmType'], equals('Map'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Map'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(2));
    expect(result.count, equals(1));
    final associations = result.associations!;
    expect(associations.length, equals(1));
    expect(associations[0].key is InstanceRef, true);
    expect(associations[0].key.kind, InstanceKind.kString);
    expect(associations[0].key.valueAsString, equals('z'));
    expect(associations[0].value is InstanceRef, true);
    expect(associations[0].value.kind, InstanceKind.kInt);
    expect(associations[0].value.valueAsString, equals('5'));
  },

  // Map with wacky offset
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart map.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getMap', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 100,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kMap);
    expect(result.json!['_vmType'], equals('Map'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Map'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(3));
    expect(result.count, equals(0));
    expect(result.associations, isEmpty);
  },

  // A built-in Set.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart set.
    final evalResult = await service
        .invoke(isolateId, isolate.rootLib!.id!, 'getSet', []) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kSet);
    expect(result.json!['_vmType'], equals('Set'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Set'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, isNull);
    final elements = result.elements!;
    expect(elements.length, equals(3));
    expect(elements[0] is InstanceRef, true);
    expect(elements[0].kind, InstanceKind.kInt);
    expect(elements[0].valueAsString, equals('6'));
    expect(elements[1] is InstanceRef, true);
    expect(elements[1].kind, InstanceKind.kInt);
    expect(elements[1].valueAsString, equals('7'));
    expect(elements[2] is InstanceRef, true);
    expect(elements[2].kind, InstanceKind.kInt);
    expect(elements[2].valueAsString, equals('8'));
  },

  // Uint8List.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint8List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kUint8List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint8List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, isNull);
    expect(result.bytes, equals('AwIB'));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint8List().toString(), equals('[3, 2, 1]'));
  },

  // Uint8List prefix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint8List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result =
        await service.getObject(isolateId, objectId, count: 2) as Instance;
    expect(result.kind, InstanceKind.kUint8List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint8List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, equals(2));
    expect(result.bytes, equals('AwI='));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint8List().toString(), equals('[3, 2]'));
  },

  // Uint8List suffix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint8List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 2,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kUint8List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint8List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(2));
    expect(result.count, equals(1));
    expect(result.bytes, equals('AQ=='));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint8List().toString(), equals('[1]'));
  },

  // Uint8List with wacky offset.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint8List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 100,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kUint8List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint8List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(3));
    expect(result.count, equals(0));
    expect(result.bytes, equals(''));
  },

  // Uint64List.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint64List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kUint64List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint64List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, isNull);
    expect(result.bytes, equals('AwAAAAAAAAACAAAAAAAAAAEAAAAAAAAA'));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint64List().toString(), equals('[3, 2, 1]'));
  },

  // Uint64List prefix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint64List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result =
        await service.getObject(isolateId, objectId, count: 2) as Instance;
    expect(result.kind, InstanceKind.kUint64List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint64List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, isNull);
    expect(result.count, equals(2));
    expect(result.bytes, equals('AwAAAAAAAAACAAAAAAAAAA=='));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint64List().toString(), equals('[3, 2]'));
  },

  // Uint64List suffix.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint64List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 2,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kUint64List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint64List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(2));
    expect(result.count, equals(1));
    expect(result.bytes, equals('AQAAAAAAAAA='));
    final Uint8List bytes = base64Decode(result.bytes!);
    expect(bytes.buffer.asUint64List().toString(), equals('[1]'));
  },

  // Uint64List with wacky offset.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart list.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getUint64List',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(
      isolateId,
      objectId,
      offset: 100,
      count: 2,
    ) as Instance;
    expect(result.kind, InstanceKind.kUint64List);
    expect(result.json!['_vmType'], equals('TypedData'));
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, equals('_Uint64List'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, equals(3));
    expect(result.offset, equals(3));
    expect(result.count, equals(0));
    expect(result.bytes, equals(''));
  },

  // An expired object.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'objects/99999999/0';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got object with bad ID');
    } on SentinelException catch (e) {
      expect(e.sentinel.kind, startsWith('Expired'));
      expect(e.sentinel.valueAsString, equals('<expired>'));
    }
  },

  // A record.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a Dart record.
    final evalResult =
        await service.invoke(isolateId, isolate.rootLib!.id!, 'getRecord', [])
            as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kRecord);
    expect(result.json!['_vmType'], 'Record');
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, '_Record');
    expect(result.size, isPositive);
    expect(result.length, 4);
    final fieldsMap = HashMap.fromEntries(
      result.fields!.map((f) => MapEntry(f.name, f.value)),
    );
    expect(fieldsMap.keys.length, result.length);
    // [BoundField]s have fields with type [dynamic], and such fields have
    // broken [toJson()] in the past. So, we make the following call just to
    // ensure that it doesn't throw.
    result.fields!.first.toJson();
    expect(fieldsMap.containsKey(0), false);
    expect(fieldsMap.containsKey(1), true);
    expect(fieldsMap[1].valueAsString, '1');
    expect(fieldsMap.containsKey('x'), true);
    expect(fieldsMap['x'].valueAsString, '2');
    expect(fieldsMap.containsKey(2), true);
    expect(fieldsMap[2].valueAsString, '3.0');
    expect(fieldsMap.containsKey('y'), true);
    expect(fieldsMap['y'].valueAsString, '4.0');
  },

  // library.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final result =
        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
    expect(result.id, startsWith('libraries/'));
    expect(result.name, equals('get_object_rpc_test'));
    expect(result.uri, startsWith('file:'));
    expect(result.uri, endsWith('get_object_rpc_test.dart'));
    expect(result.debuggable, equals(true));
    expect(result.dependencies!.length, isPositive);
    expect(result.dependencies![0].target, isNotNull);
    expect(result.scripts!.length, isPositive);
    expect(result.variables!.length, isPositive);
    expect(result.functions!.length, isPositive);
    expect(result.classes!.length, isPositive);
  },

  // invalid library.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'libraries/9999999';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got library with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // script.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Get the library first.
    final libResult =
        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
    // Get the first script.
    final result =
        await service.getObject(isolateId, libResult.scripts![0].id!) as Script;
    expect(result.id, startsWith('libraries/'));
    expect(result.uri, startsWith('file:'));
    expect(result.uri, endsWith('get_object_rpc_test.dart'));
    expect(result.json!['_kind'], equals('kernel'));
    expect(result.library, isNotNull);
    expect(result.source, startsWith('// Copyright (c)'));
    final tokenPosTable = result.tokenPosTable!;
    expect(tokenPosTable.length, isPositive);
    expect(tokenPosTable[0], isA<List>());
    expect(tokenPosTable[0].length, isPositive);
    expect(tokenPosTable[0][0], isA<int>());
  },

  // invalid script.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'scripts/9999999';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got script with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // A PlainInstance.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kPlainInstance);
    expect(result.id, startsWith('objects/'));
    expect(result.valueAsString, isNull);
    expect(result.classRef!.name, '_DummyClass');
    expect(result.name, isNull);
    expect(result.typeParameters, isNull);
    expect(result.size, isPositive);
    expect(result.length, 3);
    final fieldsMap = HashMap.fromEntries(
      result.fields!.map((f) => MapEntry(f.name, f.value)),
    );
    expect(fieldsMap.keys.length, result.length);
    expect(fieldsMap.containsKey('dummyList'), true);
    expect((fieldsMap['dummyList'] as InstanceRef).kind, InstanceKind.kList);
    expect(fieldsMap.containsKey('dummyLateVarWithInit'), true);
    expect(
      (fieldsMap['dummyLateVarWithInit'] as Sentinel).kind,
      SentinelKind.kNotInitialized,
    );
    expect(fieldsMap.containsKey('dummyLateVar'), true);
    expect(
      (fieldsMap['dummyLateVar'] as Sentinel).kind,
      SentinelKind.kNotInitialized,
    );
  },

  // An abstract base mixin class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyClass].
    final invokeResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final derivedClass =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    final baseClassRef = derivedClass.superClass!;
    final result =
        await service.getObject(isolateId, baseClassRef.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummyAbstractBaseClass');
    expect(result.isAbstract, true);
    expect(result.isConst, false);
    expect(result.isSealed, false);
    expect(result.isMixinClass, true);
    expect(result.isBaseClass, true);
    expect(result.isInterfaceClass, false);
    expect(result.isFinal, false);
    expect(result.typeParameters, isNull);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 0);
    expect(result.functions!.length, 2);
    expect(result.subclasses!.length, 1);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummyAbstractBaseClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // A class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyClass].
    final invokeResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final result =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummyClass');
    expect(result.isAbstract, false);
    expect(result.isConst, false);
    expect(result.isSealed, false);
    expect(result.isMixinClass, false);
    expect(result.isBaseClass, true);
    expect(result.isInterfaceClass, false);
    expect(result.isFinal, false);
    expect(result.typeParameters, isNull);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 5);
    expect(result.functions!.length, 12);
    expect(result.subclasses!.length, 2);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummyClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // A generic class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyGenericSubClass].
    final invokeResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyGenericSubClass',
      [],
    ) as InstanceRef;
    final result =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummyGenericSubClass');
    expect(result.isAbstract, false);
    expect(result.isConst, false);
    expect(result.isSealed, false);
    expect(result.isMixinClass, false);
    expect(result.isBaseClass, true);
    expect(result.isInterfaceClass, false);
    expect(result.isFinal, false);
    expect(result.typeParameters!.length, 1);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 0);
    expect(result.functions!.length, 1);
    expect(result.subclasses!.length, 0);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummyGenericSubClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // A final class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyFinalClass].
    final invokeResult = await service
            .invoke(isolateId, isolate.rootLib!.id!, 'getDummyFinalClass', [])
        as InstanceRef;
    final result =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummyFinalClass');
    expect(result.isAbstract, false);
    expect(result.isConst, false);
    expect(result.isSealed, false);
    expect(result.isMixinClass, false);
    expect(result.isBaseClass, false);
    expect(result.isInterfaceClass, false);
    expect(result.isFinal, true);
    expect(result.typeParameters, isNull);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 0);
    expect(result.functions!.length, 1);
    expect(result.subclasses!.length, 0);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummyFinalClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // A sealed class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyInterfaceClass].
    final invokeResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyInterfaceClass',
      [],
    ) as InstanceRef;
    final derivedClass =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    final baseClassRef = derivedClass.superClass!;
    final result =
        await service.getObject(isolateId, baseClassRef.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummySealedClass');
    expect(result.isAbstract, true);
    expect(result.isConst, false);
    expect(result.isSealed, true);
    expect(result.isMixinClass, false);
    expect(result.isBaseClass, false);
    expect(result.isInterfaceClass, false);
    expect(result.isFinal, false);
    expect(result.typeParameters, isNull);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 0);
    expect(result.functions!.length, 1);
    expect(result.subclasses!.length, 1);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummySealedClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // An interface class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyInterfaceClass].
    final invokeResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyInterfaceClass',
      [],
    ) as InstanceRef;
    final result =
        await service.getObject(isolateId, invokeResult.classRef!.id!) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, '_DummyInterfaceClass');
    expect(result.isAbstract, false);
    expect(result.isConst, false);
    expect(result.isSealed, false);
    expect(result.isMixinClass, false);
    expect(result.isBaseClass, false);
    expect(result.isInterfaceClass, true);
    expect(result.isFinal, false);
    expect(result.typeParameters, isNull);
    expect(result.library, isNotNull);
    expect(result.location, isNotNull);
    expect(result.error, isNull);
    expect(result.traceAllocations!, false);
    expect(result.superClass, isNotNull);
    expect(result.superType, isNotNull);
    expect(result.interfaces!.length, 0);
    expect(result.mixin, isNull);
    expect(result.fields!.length, 0);
    expect(result.functions!.length, 1);
    expect(result.subclasses!.length, 0);
    final json = result.json!;
    expect(json['_vmName'], startsWith('_DummyInterfaceClass@'));
    expect(json['_finalized'], true);
    expect(json['_implemented'], false);
    expect(json['_patch'], false);
  },

  // A class with final and sealed mixins.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Use invoke to get a reference to an instance of [_DummyClassWithMixins].
    final dummyClassInstanceRef = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClassWithMixins',
      [],
    ) as InstanceRef;
    final dummyClass = await service.getObject(
      isolateId,
      dummyClassInstanceRef.classRef!.id!,
    ) as Class;

    final dummyClassWithTwoMixinsApplied =
        await service.getObject(isolateId, dummyClass.superClass!.id!) as Class;
    expect(dummyClassWithTwoMixinsApplied.id, startsWith('classes/'));
    expect(
      dummyClassWithTwoMixinsApplied.name,
      '__DummyClassWithMixins&Object&_DummyBaseMixin&_DummyMixin',
    );
    expect(dummyClassWithTwoMixinsApplied.isAbstract, true);
    expect(dummyClassWithTwoMixinsApplied.isConst, true);
    expect(dummyClassWithTwoMixinsApplied.isSealed, false);
    expect(dummyClassWithTwoMixinsApplied.isMixinClass, false);
    expect(dummyClassWithTwoMixinsApplied.isBaseClass, false);
    expect(dummyClassWithTwoMixinsApplied.isInterfaceClass, false);
    expect(dummyClassWithTwoMixinsApplied.isFinal, true);
    expect(dummyClassWithTwoMixinsApplied.typeParameters, isNull);
    expect(dummyClassWithTwoMixinsApplied.library, isNotNull);
    expect(dummyClassWithTwoMixinsApplied.location, isNotNull);
    expect(dummyClassWithTwoMixinsApplied.error, isNull);
    expect(dummyClassWithTwoMixinsApplied.traceAllocations!, false);
    expect(dummyClassWithTwoMixinsApplied.superType, isNotNull);
    expect(dummyClassWithTwoMixinsApplied.fields!.length, 0);
    expect(dummyClassWithTwoMixinsApplied.functions!.length, 2);
    expect(dummyClassWithTwoMixinsApplied.subclasses!.length, 1);
    final dummyClassWithTwoMixinsAppliedJson =
        dummyClassWithTwoMixinsApplied.json!;
    expect(
      dummyClassWithTwoMixinsAppliedJson['_vmName'],
      startsWith(
        '__DummyClassWithMixins&Object&_DummyBaseMixin&_DummyMixin@',
      ),
    );
    expect(dummyClassWithTwoMixinsAppliedJson['_finalized'], true);
    expect(dummyClassWithTwoMixinsAppliedJson['_implemented'], false);
    expect(dummyClassWithTwoMixinsAppliedJson['_patch'], false);

    expect(dummyClassWithTwoMixinsApplied.interfaces!.length, 1);
    expect(
      dummyClassWithTwoMixinsApplied.interfaces!.first,
      dummyClassWithTwoMixinsApplied.mixin!,
    );
    final dummyMixinType = await service.getObject(
      isolateId,
      dummyClassWithTwoMixinsApplied.mixin!.id!,
    ) as Instance;
    expect(dummyMixinType.kind, InstanceKind.kType);
    expect(dummyMixinType.id, startsWith('classes/'));
    expect(dummyMixinType.name, '_DummyMixin');
    final dummyMixinClass = await service.getObject(
      isolateId,
      dummyMixinType.typeClass!.id!,
    ) as Class;
    expect(dummyMixinClass.id, startsWith('classes/'));
    expect(dummyMixinClass.name, '_DummyMixin');
    expect(dummyMixinClass.isAbstract, true);
    expect(dummyMixinClass.isConst, false);
    expect(dummyMixinClass.isSealed, false);
    expect(dummyMixinClass.isMixinClass, false);
    expect(dummyMixinClass.isBaseClass, false);
    expect(dummyMixinClass.isInterfaceClass, false);
    expect(dummyMixinClass.isFinal, false);
    expect(dummyMixinClass.typeParameters, isNull);
    expect(dummyMixinClass.library, isNotNull);
    expect(dummyMixinClass.location, isNotNull);
    expect(dummyMixinClass.error, isNull);
    expect(dummyMixinClass.traceAllocations!, false);
    expect(dummyMixinClass.superType, isNotNull);
    expect(dummyMixinClass.fields!.length, 0);
    expect(dummyMixinClass.functions!.length, 1);
    expect(dummyMixinClass.subclasses!.length, 0);
    expect(dummyMixinClass.interfaces!.length, 0);
    expect(dummyMixinClass.mixin, isNull);
    final dummyMixinClassJson = dummyMixinClass.json!;
    expect(dummyMixinClassJson['_vmName'], startsWith('_DummyMixin@'));
    expect(dummyMixinClassJson['_finalized'], true);
    expect(dummyMixinClassJson['_implemented'], true);
    expect(dummyMixinClassJson['_patch'], false);

    final dummyClassWithOneMixinApplied = await service.getObject(
      isolateId,
      dummyClassWithTwoMixinsApplied.superClass!.id!,
    ) as Class;
    expect(dummyClassWithOneMixinApplied.id, startsWith('classes/'));
    expect(
      dummyClassWithOneMixinApplied.name,
      '__DummyClassWithMixins&Object&_DummyBaseMixin',
    );
    expect(dummyClassWithOneMixinApplied.isAbstract, true);
    expect(dummyClassWithOneMixinApplied.isConst, true);
    expect(dummyClassWithOneMixinApplied.isSealed, false);
    expect(dummyClassWithOneMixinApplied.isMixinClass, false);
    expect(dummyClassWithOneMixinApplied.isBaseClass, false);
    expect(dummyClassWithOneMixinApplied.isInterfaceClass, false);
    expect(dummyClassWithOneMixinApplied.isFinal, true);
    expect(dummyClassWithOneMixinApplied.typeParameters, isNull);
    expect(dummyClassWithOneMixinApplied.library, isNotNull);
    expect(dummyClassWithOneMixinApplied.location, isNotNull);
    expect(dummyClassWithOneMixinApplied.error, isNull);
    expect(dummyClassWithOneMixinApplied.traceAllocations!, false);
    expect(dummyClassWithOneMixinApplied.superType, isNotNull);
    expect(dummyClassWithOneMixinApplied.fields!.length, 0);
    expect(dummyClassWithOneMixinApplied.functions!.length, 2);
    expect(dummyClassWithOneMixinApplied.subclasses!.length, 1);
    final dummyClassWithOneMixinAppliedJson =
        dummyClassWithOneMixinApplied.json!;
    expect(
      dummyClassWithOneMixinAppliedJson['_vmName'],
      startsWith('__DummyClassWithMixins&Object&_DummyBaseMixin@'),
    );
    expect(dummyClassWithOneMixinAppliedJson['_finalized'], true);
    expect(dummyClassWithOneMixinAppliedJson['_implemented'], false);
    expect(dummyClassWithOneMixinAppliedJson['_patch'], false);

    expect(dummyClassWithOneMixinApplied.interfaces!.length, 1);
    expect(
      dummyClassWithOneMixinApplied.interfaces!.first,
      dummyClassWithOneMixinApplied.mixin!,
    );
    final dummyBaseMixinType = await service.getObject(
      isolateId,
      dummyClassWithOneMixinApplied.mixin!.id!,
    ) as Instance;
    expect(dummyBaseMixinType.kind, InstanceKind.kType);
    expect(dummyBaseMixinType.id, startsWith('classes/'));
    expect(dummyBaseMixinType.name, '_DummyBaseMixin');
    final dummyBaseMixinClass = await service.getObject(
      isolateId,
      dummyBaseMixinType.typeClass!.id!,
    ) as Class;
    expect(dummyBaseMixinClass.id, startsWith('classes/'));
    expect(dummyBaseMixinClass.name, '_DummyBaseMixin');
    expect(dummyBaseMixinClass.isAbstract, true);
    expect(dummyBaseMixinClass.isConst, false);
    expect(dummyBaseMixinClass.isSealed, false);
    expect(dummyBaseMixinClass.isMixinClass, false);
    expect(dummyBaseMixinClass.isBaseClass, true);
    expect(dummyBaseMixinClass.isInterfaceClass, false);
    expect(dummyBaseMixinClass.isFinal, false);
    expect(dummyBaseMixinClass.typeParameters, isNull);
    expect(dummyBaseMixinClass.library, isNotNull);
    expect(dummyBaseMixinClass.location, isNotNull);
    expect(dummyBaseMixinClass.error, isNull);
    expect(dummyBaseMixinClass.traceAllocations!, false);
    expect(dummyBaseMixinClass.superType, isNotNull);
    expect(dummyBaseMixinClass.fields!.length, 0);
    expect(dummyBaseMixinClass.functions!.length, 1);
    expect(dummyBaseMixinClass.subclasses!.length, 0);
    expect(dummyBaseMixinClass.interfaces!.length, 0);
    expect(dummyBaseMixinClass.mixin, isNull);
    final dummyBaseMixinClassJson = dummyBaseMixinClass.json!;
    expect(dummyBaseMixinClassJson['_vmName'], startsWith('_DummyBaseMixin@'));
    expect(dummyBaseMixinClassJson['_finalized'], true);
    expect(dummyBaseMixinClassJson['_implemented'], true);
    expect(dummyBaseMixinClassJson['_patch'], false);
  },

  // invalid class.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'scripts/9999999';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got class with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // type.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/types/0';
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kType);
    expect(result.id, equals(objectId));
    expect(result.classRef!.name, equals('_Type'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.typeClass!.name, equals('_DummyClass'));
  },

  // invalid type.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/types/9999999';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got type with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // function.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/functions/dummyFunction';
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyFunction'));
    expect(result.isStatic, equals(false));
    expect(result.isConst, equals(false));
    expect(result.implicit, equals(false));
    expect(result.isAbstract, equals(false));
    expect(result.isGetter, false);
    expect(result.isSetter, false);
    final signature = result.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    final parameters = signature.parameters!;
    expect(parameters.length, 3);
    expect(parameters[1].parameterType!.name, equals('int'));
    expect(parameters[1].fixed, isTrue);
    expect(parameters[2].parameterType!.name, equals('bool'));
    expect(parameters[2].fixed, isFalse);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], equals('RegularFunction'));
    expect(json['_optimizable'], equals(true));
    expect(json['_inlinable'], equals(true));
    expect(json['_usageCounter'], isPositive);
    expect(json['_optimizedCallSiteCount'], isZero);
    expect(json['_deoptimizations'], isZero);
  },

  // generic function.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId =
        '${evalResult.classRef!.id!}/functions/dummyGenericFunction';
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyGenericFunction'));
    expect(result.isStatic, equals(false));
    expect(result.isConst, equals(false));
    expect(result.implicit, equals(false));
    expect(result.isAbstract, equals(false));
    expect(result.isGetter, false);
    expect(result.isSetter, false);
    final signature = result.signature!;
    expect(signature.typeParameters!.length, 2);
    expect(signature.returnType, isNotNull);
    final parameters = signature.parameters!;
    expect(parameters.length, 3);
    expect(parameters[1].parameterType!.name, isNotNull);
    expect(parameters[1].fixed, isTrue);
    expect(parameters[2].parameterType!.name, isNotNull);
    expect(parameters[2].name, 'param');
    expect(parameters[2].fixed, isFalse);
    expect(parameters[2].required, isTrue);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], equals('RegularFunction'));
    expect(json['_optimizable'], equals(true));
    expect(json['_inlinable'], equals(true));
    expect(json['_usageCounter'], isPositive);
    expect(json['_optimizedCallSiteCount'], isZero);
    expect(json['_deoptimizations'], isZero);
  },

  // abstract function.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = evalResult.classRef!.id!;
    final result = await service.getObject(isolateId, objectId) as Class;
    expect(result.id, startsWith('classes/'));
    expect(result.name, equals('_DummyClass'));
    expect(result.isAbstract, equals(false));

    // Get the super class.
    final superClass =
        await service.getObject(isolateId, result.superClass!.id!) as Class;
    expect(superClass.id, startsWith('classes/'));
    expect(superClass.name, equals('_DummyAbstractBaseClass'));
    expect(superClass.isAbstract, equals(true));

    // Find the abstract dummyFunction on the super class.
    final funcId =
        superClass.functions!.firstWhere((f) => f.name == 'dummyFunction').id!;
    final funcResult = await service.getObject(isolateId, funcId) as Func;

    expect(funcResult.id, equals(funcId));
    expect(funcResult.name, equals('dummyFunction'));
    expect(funcResult.isStatic, equals(false));
    expect(funcResult.isConst, equals(false));
    expect(funcResult.implicit, equals(false));
    expect(funcResult.isAbstract, equals(true));
    expect(funcResult.isGetter, false);
    expect(funcResult.isSetter, false);
    final signature = funcResult.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    final parameters = signature.parameters!;
    expect(parameters.length, 3);
    expect(parameters[1].parameterType!.name, equals('int'));
    expect(parameters[1].fixed, isTrue);
    expect(parameters[2].parameterType!.name, equals('bool'));
    expect(parameters[2].fixed, isFalse);
    expect(funcResult.location, isNotNull);
    expect(funcResult.code, isNotNull);
    final json = funcResult.json!;
    expect(json['_kind'], equals('RegularFunction'));
    expect(json['_optimizable'], equals(true));
    expect(json['_inlinable'], equals(true));
    expect(json['_usageCounter'], isZero);
    expect(json['_optimizedCallSiteCount'], isZero);
    expect(json['_deoptimizations'], isZero);
  },

  // invalid function.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/functions/invalid';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got function with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // field
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/fields/dummyVar';
    final result = await service.getObject(isolateId, objectId) as Field;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyVar'));
    expect(result.isConst, equals(false));
    expect(result.isStatic, equals(true));
    expect(result.isFinal, equals(false));
    expect(result.location, isNotNull);
    expect(result.staticValue.valueAsString, equals('11'));
    final json = result.json!;
    expect(json['_guardNullable'], isNotNull);
    expect(json['_guardClass'], isNotNull);
    expect(json['_guardLength'], isNotNull);
  },

  // getter
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId =
        "${evalResult.classRef!.id!}/functions/get${Uri.encodeComponent(':')}dummyVarGetter";
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, objectId);
    expect(result.name, 'dummyVarGetter');
    expect(result.isStatic, false);
    expect(result.isConst, false);
    expect(result.implicit, false);
    expect(result.isAbstract, false);
    expect(result.isGetter, true);
    expect(result.isSetter, false);
    final signature = result.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    final parameters = signature.parameters!;
    expect(parameters.length, 1);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], 'GetterFunction');
    expect(json['_optimizable'], true);
    expect(json['_inlinable'], true);
    expect(json['_usageCounter'], 0);
    expect(json['_optimizedCallSiteCount'], 0);
    expect(json['_deoptimizations'], 0);
  },

  // setter
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId =
        "${evalResult.classRef!.id!}/functions/set${Uri.encodeComponent(':')}dummyVarSetter";
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, objectId);
    expect(result.name, 'dummyVarSetter=');
    expect(result.isStatic, false);
    expect(result.isConst, false);
    expect(result.implicit, false);
    expect(result.isAbstract, false);
    expect(result.isGetter, false);
    expect(result.isSetter, true);
    final signature = result.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    final parameters = signature.parameters!;
    expect(parameters.length, 2);
    expect(parameters[1].parameterType!.name, equals('int'));
    expect(parameters[1].fixed, isTrue);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], 'SetterFunction');
    expect(json['_optimizable'], true);
    expect(json['_inlinable'], true);
    expect(json['_usageCounter'], 0);
    expect(json['_optimizedCallSiteCount'], 0);
    expect(json['_deoptimizations'], 0);
  },

  // static field initializer
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/field_inits/dummyVarWithInit';
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyVarWithInit'));
    expect(result.isStatic, equals(true));
    expect(result.isConst, equals(false));
    expect(result.implicit, equals(false));
    expect(result.isAbstract, equals(false));
    expect(result.isGetter, false);
    expect(result.isSetter, false);
    final signature = result.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    expect(signature.parameters!.length, 0);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], equals('FieldInitializer'));
    expect(json['_optimizable'], equals(true));
    expect(json['_inlinable'], equals(false));
    expect(json['_usageCounter'], isZero);
    expect(json['_optimizedCallSiteCount'], isZero);
    expect(json['_deoptimizations'], isZero);
  },

  // late field initializer
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call [invoke] to get an [InstanceRef], and then use the ID of its
    // [classRef] field to build a function ID.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId =
        '${evalResult.classRef!.id!}/field_inits/dummyLateVarWithInit';
    final result = await service.getObject(isolateId, objectId) as Func;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyLateVarWithInit'));
    expect(result.isStatic, equals(false));
    expect(result.isConst, equals(false));
    expect(result.implicit, equals(false));
    expect(result.isAbstract, equals(false));
    expect(result.isGetter, false);
    expect(result.isSetter, false);
    final signature = result.signature!;
    expect(signature.typeParameters, isNull);
    expect(signature.returnType, isNotNull);
    expect(signature.parameters!.length, 1);
    expect(result.location, isNotNull);
    expect(result.code, isNotNull);
    final json = result.json!;
    expect(json['_kind'], equals('FieldInitializer'));
    expect(json['_optimizable'], equals(true));
    expect(json['_inlinable'], equals(false));
    expect(json['_usageCounter'], isZero);
    expect(json['_optimizedCallSiteCount'], isZero);
    expect(json['_deoptimizations'], isZero);
  },

  // invalid late field initializer
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/field_inits/dummyLateVar';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got field initializer with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
    }
  },

  // field with guards
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final flagList = await service.getFlagList();
    if (!flagList.flags!.any(
      (flag) => flag.name == 'use_field_guards' && flag.valueAsString == 'true',
    )) {
      // Skip the test if guards are not enabled.
      return;
    }

    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/fields/dummyList';
    final result = await service.getObject(isolateId, objectId) as Field;
    expect(result.id, equals(objectId));
    expect(result.name, equals('dummyList'));
    expect(result.isConst, equals(false));
    expect(result.isStatic, equals(false));
    expect(result.isFinal, equals(true));
    expect(result.location, isNotNull);
    final json = result.json!;
    expect(json['_guardNullable'], isNotNull);
    expect(json['_guardClass'], isNotNull);
    expect(json['_guardLength'], equals('20'));
  },

  // invalid field.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/fields/mythicalField';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got field with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
    }
  },

  // UserTag
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a UserTag id.
    final evalResult =
        await service.invoke(isolateId, isolate.rootLib!.id!, 'getUserTag', [])
            as InstanceRef;
    final result =
        await service.getObject(isolateId, evalResult.id!) as Instance;
    expect(result.label, equals('Test Tag'));
  },

  // code.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    // Call eval to get a class id.
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getDummyClass',
      [],
    ) as InstanceRef;
    final objectId = '${evalResult.classRef!.id!}/functions/dummyFunction';
    final funcResult = await service.getObject(isolateId, objectId) as Func;
    final result =
        await service.getObject(isolateId, funcResult.code!.id!) as Code;
    expect(result.name, endsWith('_DummyClass.dummyFunction'));
    expect(result.kind, CodeKind.kDart);
    final json = result.json!;
    expect(json['_vmName'], endsWith('dummyFunction'));
    expect(json['_optimized'], isA<bool>());
    expect(json['function']['type'], equals('@Function'));
    expect(json['_startAddress'], isA<String>());
    expect(json['_endAddress'], isA<String>());
    expect(json['_objectPool'], isNotNull);
    expect(json['_disassembly'], isNotNull);
    expect(json['_descriptors'], isNotNull);
    expect(json['_inlinedFunctions'], anyOf([isNull, isA<List>()]));
    expect(json['_inlinedIntervals'], anyOf([isNull, isA<List>()]));
  },

  // invalid code.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final objectId = 'code/0';
    try {
      await service.getObject(isolateId, objectId);
      fail('successfully got code with bad ID');
    } on RPCError catch (e) {
      expect(e.code, equals(RPCErrorKind.kInvalidParams.code));
      expect(e.message, 'Invalid params');
    }
  },

  // A finalizer
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getFinalizer',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kFinalizer);
    expect(result.json!['_vmType'], equals('Finalizer'));
    expect(result.id, startsWith('objects/'));
    expect(result.classRef!.name, equals('_FinalizerImpl'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, isNull);
    expect(result.offset, isNull);
    expect(result.count, isNull);
    final callback = result.callback;
    expect(callback, isNotNull);
    expect(callback!.kind, equals(InstanceKind.kClosure));
    final allEntriesRef = result.allEntries;
    expect(allEntriesRef, isNotNull);
    final allEntries =
        await service.getObject(isolateId, allEntriesRef!.id!) as Instance;
    for (final entryRef in allEntries.elements!) {
      final entry =
          await service.getObject(isolateId, entryRef!.id!) as Instance;
      expect(entry.kind, InstanceKind.kFinalizerEntry);
      expect(entry.json!['_vmType'], equals('FinalizerEntry'));
      expect(entry.id, startsWith('objects/'));
      expect(entry.classRef!.name, equals('FinalizerEntry'));
      expect(entry.size, isPositive);
      expect(entry.fields, isEmpty);
      expect(entry.length, isNull);
      expect(entry.offset, isNull);
      expect(entry.count, isNull);
      expect(entry.value!.classRef!.name, '_DummyClass');
      expect(entry.token!.classRef!.name, '_DummyClass');
      expect(entry.detach!.classRef!.name, '_DummyClass');
    }
  },

  // A native finalizer
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final evalResult = await service.invoke(
      isolateId,
      isolate.rootLib!.id!,
      'getNativeFinalizer',
      [],
    ) as InstanceRef;
    final objectId = evalResult.id!;
    final result = await service.getObject(isolateId, objectId) as Instance;
    expect(result.kind, InstanceKind.kNativeFinalizer);
    expect(result.json!['_vmType'], equals('NativeFinalizer'));
    expect(result.id, startsWith('objects/'));
    expect(result.classRef!.name, equals('_NativeFinalizer'));
    expect(result.size, isPositive);
    expect(result.fields, isEmpty);
    expect(result.length, isNull);
    expect(result.offset, isNull);
    expect(result.count, isNull);
    final callbackAddress = result.callbackAddress;
    expect(callbackAddress, isNotNull);
    expect(callbackAddress!.classRef!.name, equals('Pointer'));
    final allEntriesRef = result.allEntries;
    expect(allEntriesRef, isNotNull);
    final allEntries =
        await service.getObject(isolateId, allEntriesRef!.id!) as Instance;
    expect(allEntries.elements, isEmpty);
  },
];

void main([args = const <String>[]]) => runIsolateTests(
      args,
      tests,
      'get_object_rpc_test.dart',
      testeeBefore: warmup,
    );
