Files
sdk/pkg/analysis_server/test/mocks_lsp.dart
Paul Berry afcfbbeba8 Migrate developer experience packages to new constructor decl syntax.
(Part of https://github.com/dart-lang/sdk/issues/63288)

This change migrates the packages owned by the developer experience
team to use the new constructor declaration syntax, described in
https://github.com/dart-lang/language/blob/main/accepted/future-releases/primary-constructors/feature-specification.md#abbreviations-of-in-body-constructor-declarations.

This change was performed in an automated fashion, by (a) bumping the
packages' SDK constraints to `3.13.0-0`, (b) enabling the lints
`unnecessary_type_name_in_constructor` and
`unnecessary_const_in_enum_constructor`, (c) fixing the resulting lint
failures using `dart fix`, and then (d) reformatting the affected
files.

To ease code review, I've reverted unrelated formatting changes.

Since this change requires bumping SDK constaints to `3.13.0-0`, it
was only performed on packages that are *not* published on
pub. (Packages that *are* published on pub should remain on lower
language versions until at least after the stable version of 3.13 is
released, so that we don't block users on the stable channel from
receiving updates to those packages.)

Change-Id: Ibb4daebafd239da58251e838ea6a3f336a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505046
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com>
2026-05-27 14:52:58 -07:00

191 lines
5.9 KiB
Dart

// Copyright (c) 2014, 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 'dart:convert';
import 'package:analysis_server/lsp_protocol/protocol.dart' as lsp;
import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
/// A mock [LspServerCommunicationChannel] for testing [LspAnalysisServer].
class MockLspServerChannel implements LspServerCommunicationChannel {
final StreamController<lsp.Message> _clientToServer =
StreamController<lsp.Message>.broadcast();
final StreamController<lsp.Message> _serverToClient =
StreamController<lsp.Message>.broadcast();
/// Completer that will be signalled when the input stream is closed.
final Completer<void> _closed = Completer();
/// Errors popups sent to the user.
final shownErrors = <lsp.ShowMessageParams>[];
/// Warning popups sent to the user.
final shownWarnings = <lsp.ShowMessageParams>[];
new(bool printMessages) {
if (printMessages) {
_serverToClient.stream.listen(
(message) => print('<== ${jsonEncode(message)}'),
);
_clientToServer.stream.listen(
(message) => print('==> ${jsonEncode(message)}'),
);
}
// Keep track of any errors/warnings that are sent to the user with
// `window/showMessage`.
_serverToClient.stream.listen((message) {
if (message is lsp.NotificationMessage &&
message.method == lsp.Method.window_showMessage) {
var params = message.params;
if (params is lsp.ShowMessageParams) {
if (params.type == lsp.MessageType.Error) {
shownErrors.add(params);
} else if (params.type == lsp.MessageType.Warning) {
shownWarnings.add(params);
}
}
}
});
}
/// Future that will be completed when the input stream is closed.
@override
Future<void> get closed {
return _closed.future;
}
Stream<lsp.Message> get serverToClient => _serverToClient.stream;
@override
void close() {
if (!_closed.isCompleted) {
_closed.complete();
}
if (!_serverToClient.isClosed) {
_serverToClient.close();
}
if (!_clientToServer.isClosed) {
_clientToServer.close();
}
}
@override
StreamSubscription<void> listen(
void Function(lsp.Message message) onMessage, {
Function? onError,
void Function()? onDone,
}) {
return _clientToServer.stream.listen(
onMessage,
onError: onError,
onDone: onDone,
);
}
@override
void sendNotification(lsp.NotificationMessage notification) {
// Don't deliver notifications after the connection is closed.
if (_closed.isCompleted) {
return;
}
notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
_serverToClient.add(notification);
}
void sendNotificationToServer(lsp.NotificationMessage notification) {
// Don't deliver notifications after the connection is closed.
if (_closed.isCompleted) {
return;
}
notification = _convertJson(notification, lsp.NotificationMessage.fromJson);
_clientToServer.add(notification);
}
@override
void sendRequest(lsp.RequestMessage request) {
// Don't deliver notifications after the connection is closed.
if (_closed.isCompleted) {
return;
}
request = _convertJson(request, lsp.RequestMessage.fromJson);
_serverToClient.add(request);
}
/// Send the given [request] to the server and return a future that will
/// complete when a response associated with the [request] has been received.
/// The value of the future will be the received response.
Future<lsp.ResponseMessage> sendRequestToServer(lsp.RequestMessage request) {
// No further requests should be sent after the connection is closed.
if (_closed.isCompleted) {
throw Exception('${request.method} request sent after connection closed');
}
request = _convertJson(request, lsp.RequestMessage.fromJson);
_clientToServer.add(request);
return waitForResponse(request);
}
@override
void sendResponse(lsp.ResponseMessage response) {
// Don't deliver responses after the connection is closed.
if (_closed.isCompleted) {
return;
}
response = _convertJson(response, lsp.ResponseMessage.fromJson);
_serverToClient.add(response);
}
void sendResponseToServer(lsp.ResponseMessage response) {
// Don't deliver notifications after the connection is closed.
if (_closed.isCompleted) {
return;
}
response = _convertJson(response, lsp.ResponseMessage.fromJson);
_clientToServer.add(response);
}
/// Return a future that will complete when a response associated with the
/// given [request] has been received. The value of the future will be the
/// received response. The returned future will throw an exception if a server
/// error is reported before the response has been received.
///
/// Unlike [sendRequestToServer], this method assumes that the [request] has
/// already been sent to the server.
Future<lsp.ResponseMessage> waitForResponse(
lsp.RequestMessage request,
) async {
var response = await _serverToClient.stream.firstWhere(
(message) => message is lsp.ResponseMessage && message.id == request.id,
);
return response as lsp.ResponseMessage;
}
/// Round trips the object to JSON and back to ensure it behaves the same as
/// when running over the real STDIO server. Without this, the object passed
/// to the handlers will have concrete types as constructed in tests rather
/// than the maps as they would be (the server expects to do the conversion).
T _convertJson<T>(
lsp.ToJsonable message,
T Function(Map<String, dynamic>) constructor,
) {
return constructor(
jsonDecode(jsonEncode(message.toJson())) as Map<String, Object?>,
);
}
}