| // Copyright 2014 The Flutter Authors. 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:flutter_tools/src/convert.dart'; |
| import 'package:flutter_tools/src/vmservice.dart'; |
| import 'package:test_api/test_api.dart' hide test; // ignore: deprecated_member_use |
| import 'package:vm_service/vm_service.dart' as vm_service; |
| |
| export 'package:test_api/test_api.dart' hide isInstanceOf, test; // ignore: deprecated_member_use |
| |
| /// A fake implementation of a vm_service that mocks the JSON-RPC request |
| /// and response structure. |
| class FakeVmServiceHost { |
| FakeVmServiceHost({ |
| required List<VmServiceExpectation> requests, |
| Uri? httpAddress, |
| Uri? wsAddress, |
| }) : _requests = requests { |
| _vmService = FlutterVmService(vm_service.VmService( |
| _input.stream, |
| _output.add, |
| ), httpAddress: httpAddress, wsAddress: wsAddress); |
| _applyStreamListen(); |
| _output.stream.listen((String data) { |
| final Map<String, Object?> request = json.decode(data) as Map<String, Object?>; |
| if (_requests.isEmpty) { |
| throw Exception('Unexpected request: $request'); |
| } |
| final FakeVmServiceRequest fakeRequest = _requests.removeAt(0) as FakeVmServiceRequest; |
| expect(request, isA<Map<String, Object?>>() |
| .having((Map<String, Object?> request) => request['method'], 'method', fakeRequest.method) |
| .having((Map<String, Object?> request) => request['params'], 'args', fakeRequest.args) |
| ); |
| if (fakeRequest.close) { |
| unawaited(_vmService.dispose()); |
| expect(_requests, isEmpty); |
| return; |
| } |
| if (fakeRequest.errorCode == null) { |
| _input.add(json.encode(<String, Object?>{ |
| 'jsonrpc': '2.0', |
| 'id': request['id'], |
| 'result': fakeRequest.jsonResponse ?? <String, Object>{'type': 'Success'}, |
| })); |
| } else { |
| _input.add(json.encode(<String, Object?>{ |
| 'jsonrpc': '2.0', |
| 'id': request['id'], |
| 'error': <String, Object?>{ |
| 'code': fakeRequest.errorCode, |
| 'message': 'error', |
| }, |
| })); |
| } |
| _applyStreamListen(); |
| }); |
| } |
| |
| final List<VmServiceExpectation> _requests; |
| final StreamController<String> _input = StreamController<String>(); |
| final StreamController<String> _output = StreamController<String>(); |
| |
| FlutterVmService get vmService => _vmService; |
| late final FlutterVmService _vmService; |
| |
| |
| bool get hasRemainingExpectations => _requests.isNotEmpty; |
| |
| // remove FakeStreamResponse objects from _requests until it is empty |
| // or until we hit a FakeRequest |
| void _applyStreamListen() { |
| while (_requests.isNotEmpty && !_requests.first.isRequest) { |
| final FakeVmServiceStreamResponse response = _requests.removeAt(0) as FakeVmServiceStreamResponse; |
| _input.add(json.encode(<String, Object>{ |
| 'jsonrpc': '2.0', |
| 'method': 'streamNotify', |
| 'params': <String, Object>{ |
| 'streamId': response.streamId, |
| 'event': response.event.toJson(), |
| }, |
| })); |
| } |
| } |
| } |
| |
| abstract class VmServiceExpectation { |
| bool get isRequest; |
| } |
| |
| class FakeVmServiceRequest implements VmServiceExpectation { |
| const FakeVmServiceRequest({ |
| required this.method, |
| this.args = const <String, Object?>{}, |
| this.jsonResponse, |
| this.errorCode, |
| this.close = false, |
| }); |
| |
| final String method; |
| |
| /// When true, the vm service is automatically closed. |
| final bool close; |
| |
| /// If non-null, the error code for a [vm_service.RPCError] in place of a |
| /// standard response. |
| final int? errorCode; |
| final Map<String, Object?>? args; |
| final Map<String, Object?>? jsonResponse; |
| |
| @override |
| bool get isRequest => true; |
| } |
| |
| class FakeVmServiceStreamResponse implements VmServiceExpectation { |
| const FakeVmServiceStreamResponse({ |
| required this.event, |
| required this.streamId, |
| }); |
| |
| final vm_service.Event event; |
| final String streamId; |
| |
| @override |
| bool get isRequest => false; |
| } |