Split helpers out of LSP base test into a mixin
This splits the helper functions out of the abstract base test, which will allow them to be reused in integration tests that have their own transport (real stdio to a process).
Change-Id: I7777dc873582b4bacd91d998fed740ada47bd2b0
Reviewed-on: https://dart-review.googlesource.com/c/90062
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index 7afb2a5..edbad6e 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -66,7 +66,7 @@
test_uninitialized_dropsNotifications() async {
final notification =
makeNotification(new Method.fromJson('randomNotification'), null);
- final nextNotification = channel.errorNotificationsFromServer.first;
+ final nextNotification = errorNotificationsFromServer.first;
channel.sendNotificationToServer(notification);
// Wait up to 1sec to ensure no error/log notifications were sent back.
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index b4d1f9f..2fd13dc 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -30,8 +30,8 @@
final beginningOfDocument = new Range(new Position(0, 0), new Position(0, 0));
-abstract class AbstractLspAnalysisServerTest
- with ResourceProviderMixin, ClientCapabilitiesHelperMixin {
+mixin LspAnalysisServerTestMixin
+ implements ResourceProviderMixin, ClientCapabilitiesHelperMixin {
static const positionMarker = '^';
static const rangeMarkerStart = '[[';
static const rangeMarkerEnd = ']]';
@@ -39,13 +39,46 @@
static final allMarkersPattern =
new RegExp(allMarkers.map(RegExp.escape).join('|'));
- MockLspServerChannel channel;
- LspAnalysisServer server;
-
int _id = 0;
String projectFolderPath, mainFilePath;
Uri projectFolderUri, mainFileUri;
+ Stream<Message> get serverToClient;
+
+ /**
+ * A stream of [NotificationMessage]s from the server that may be errors.
+ */
+ Stream<NotificationMessage> get errorNotificationsFromServer {
+ return notificationsFromServer.where(_isErrorNotification);
+ }
+
+ /**
+ * A stream of [NotificationMessage]s from the server.
+ */
+ Stream<NotificationMessage> get notificationsFromServer {
+ return serverToClient
+ .where((m) => m is NotificationMessage)
+ .cast<NotificationMessage>();
+ }
+
+ /// Checks whether a notification is likely an error from the server (for
+ /// example a window/showMessage). This is useful for tests that want to
+ /// ensure no errors come from the server in response to notifications (which
+ /// don't have their own responses).
+ bool _isErrorNotification(NotificationMessage notification) {
+ return notification.method == Method.window_logMessage ||
+ notification.method == Method.window_showMessage;
+ }
+
+ /**
+ * A stream of [RequestMessage]s from the server.
+ */
+ Stream<RequestMessage> get requestsFromServer {
+ return serverToClient
+ .where((m) => m is RequestMessage)
+ .cast<RequestMessage>();
+ }
+
void applyChanges(
Map<String, String> fileContents,
Map<String, List<TextEdit>> changes,
@@ -158,8 +191,7 @@
changes,
),
);
- channel.sendNotificationToServer(notification);
- await pumpEventQueue();
+ sendNotificationToServer(notification);
}
Future changeWorkspaceFolders({List<Uri> add, List<Uri> remove}) async {
@@ -172,8 +204,7 @@
),
),
);
- channel.sendNotificationToServer(notification);
- await pumpEventQueue();
+ sendNotificationToServer(notification);
}
Future closeFile(Uri uri) async {
@@ -182,8 +213,7 @@
new DidCloseTextDocumentParams(
new TextDocumentIdentifier(uri.toString())),
);
- channel.sendNotificationToServer(notification);
- await pumpEventQueue();
+ sendNotificationToServer(notification);
}
Future<Object> executeCommand(Command command) async {
@@ -240,7 +270,7 @@
FutureOr<void> f(), {
Duration timeout = const Duration(seconds: 5),
}) async {
- final firstError = channel.errorNotificationsFromServer.first;
+ final firstError = errorNotificationsFromServer.first;
await f();
final notificationFromServer = await firstError.timeout(timeout);
@@ -256,7 +286,7 @@
Duration timeout = const Duration(seconds: 5),
}) async {
final firstRequest =
- channel.requestsFromServer.firstWhere((n) => n.method == method);
+ requestsFromServer.firstWhere((n) => n.method == method);
await f();
final requestFromServer = await firstRequest.timeout(timeout);
@@ -268,7 +298,7 @@
/// Sends a request to the server and unwraps the result. Throws if the
/// response was not successful or returned an error.
Future<T> expectSuccessfulResponseTo<T>(RequestMessage request) async {
- final resp = await channel.sendRequestToServer(request);
+ final resp = await sendRequestToServer(request);
if (resp.error != null) {
throw resp.error;
} else {
@@ -491,12 +521,12 @@
),
null,
workspaceFolders?.map(toWorkspaceFolder)?.toList()));
- final response = await channel.sendRequestToServer(request);
+ final response = await sendRequestToServer(request);
expect(response.id, equals(request.id));
if (response.error == null) {
final notification = makeNotification(Method.initialized, null);
- channel.sendNotificationToServer(notification);
+ sendNotificationToServer(notification);
await pumpEventQueue();
}
@@ -530,7 +560,7 @@
new DidOpenTextDocumentParams(new TextDocumentItem(
uri.toString(), dartLanguageId, version, content)),
);
- channel.sendNotificationToServer(notification);
+ sendNotificationToServer(notification);
await pumpEventQueue();
}
@@ -621,7 +651,7 @@
String newName,
) {
final request = makeRenameRequest(version, uri, pos, newName);
- return channel.sendRequestToServer(request);
+ return sendRequestToServer(request);
}
Future replaceFile(int newVersion, Uri uri, String content) {
@@ -635,10 +665,67 @@
/// Sends [responseParams] to the server as a successful response to
/// a server-initiated [request].
void respondTo<T>(RequestMessage request, T responseParams) {
- channel.sendResponseToServer(
+ sendResponseToServer(
new ResponseMessage(request.id, responseParams, null, jsonRpcVersion));
}
+ FutureOr<void> sendNotificationToServer(NotificationMessage notification);
+
+ Future<ResponseMessage> sendRequestToServer(RequestMessage request);
+
+ void sendResponseToServer(ResponseMessage response);
+
+ WorkspaceFolder toWorkspaceFolder(Uri uri) {
+ return WorkspaceFolder(uri.toString(), path.basename(uri.toFilePath()));
+ }
+
+ Future<List<Diagnostic>> waitForDiagnostics(Uri uri) async {
+ PublishDiagnosticsParams diagnosticParams;
+ await serverToClient.firstWhere((message) {
+ if (message is NotificationMessage &&
+ message.method == Method.textDocument_publishDiagnostics) {
+ diagnosticParams = message.params;
+
+ return diagnosticParams.uri == uri.toString();
+ }
+ return false;
+ });
+ return diagnosticParams.diagnostics;
+ }
+
+ /// Removes markers like `[[` and `]]` and `^` that are used for marking
+ /// positions/ranges in strings to avoid hard-coding positions in tests.
+ String withoutMarkers(String contents) =>
+ contents.replaceAll(allMarkersPattern, '');
+
+ /// Removes range markers from strings to give accurate position offsets.
+ String withoutRangeMarkers(String contents) =>
+ contents.replaceAll(rangeMarkerStart, '').replaceAll(rangeMarkerEnd, '');
+}
+
+abstract class AbstractLspAnalysisServerTest
+ with
+ ResourceProviderMixin,
+ ClientCapabilitiesHelperMixin,
+ LspAnalysisServerTestMixin {
+ MockLspServerChannel channel;
+ LspAnalysisServer server;
+
+ Stream<Message> get serverToClient => channel.serverToClient;
+
+ Future sendNotificationToServer(NotificationMessage notification) async {
+ channel.sendNotificationToServer(notification);
+ await pumpEventQueue();
+ }
+
+ Future<ResponseMessage> sendRequestToServer(RequestMessage request) {
+ return channel.sendRequestToServer(request);
+ }
+
+ void sendResponseToServer(ResponseMessage response) {
+ channel.sendResponseToServer(response);
+ }
+
void setUp() {
channel = new MockLspServerChannel(debugPrintCommunication);
// Create an SDK in the mock file system.
@@ -665,33 +752,6 @@
channel.close();
await server.shutdown();
}
-
- WorkspaceFolder toWorkspaceFolder(Uri uri) {
- return WorkspaceFolder(uri.toString(), path.basename(uri.toFilePath()));
- }
-
- Future<List<Diagnostic>> waitForDiagnostics(Uri uri) async {
- PublishDiagnosticsParams diagnosticParams;
- await channel.serverToClient.firstWhere((message) {
- if (message is NotificationMessage &&
- message.method == Method.textDocument_publishDiagnostics) {
- diagnosticParams = message.params;
-
- return diagnosticParams.uri == uri.toString();
- }
- return false;
- });
- return diagnosticParams.diagnostics;
- }
-
- /// Removes markers like `[[` and `]]` and `^` that are used for marking
- /// positions/ranges in strings to avoid hard-coding positions in tests.
- String withoutMarkers(String contents) =>
- contents.replaceAll(allMarkersPattern, '');
-
- /// Removes range markers from strings to give accurate position offsets.
- String withoutRangeMarkers(String contents) =>
- contents.replaceAll(rangeMarkerStart, '').replaceAll(rangeMarkerEnd, '');
}
mixin ClientCapabilitiesHelperMixin {
diff --git a/pkg/analysis_server/test/lsp/server_test.dart b/pkg/analysis_server/test/lsp/server_test.dart
index 3be7d04..8f2525c 100644
--- a/pkg/analysis_server/test/lsp/server_test.dart
+++ b/pkg/analysis_server/test/lsp/server_test.dart
@@ -100,7 +100,7 @@
await initialize();
final notification =
makeNotification(new Method.fromJson(r'$/randomNotification'), null);
- final firstError = channel.errorNotificationsFromServer.first;
+ final firstError = errorNotificationsFromServer.first;
channel.sendNotificationToServer(notification);
// Wait up to 1sec to ensure no error/log notifications were sent back.
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 4ee6655..367e52e 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -65,31 +65,6 @@
return _closed.future;
}
- /**
- * A stream of [NotificationMessage]s from the server that may be errors.
- */
- Stream<lsp.NotificationMessage> get errorNotificationsFromServer {
- return notificationsFromServer.where(_isErrorNotification);
- }
-
- /**
- * A stream of [NotificationMessage]s from the server.
- */
- Stream<lsp.NotificationMessage> get notificationsFromServer {
- return _serverToClient.stream
- .where((m) => m is lsp.NotificationMessage)
- .cast<lsp.NotificationMessage>();
- }
-
- /**
- * A stream of [RequestMessage]s from the server.
- */
- Stream<lsp.RequestMessage> get requestsFromServer {
- return _serverToClient.stream
- .where((m) => m is lsp.RequestMessage)
- .cast<lsp.RequestMessage>();
- }
-
Stream<lsp.Message> get serverToClient => _serverToClient.stream;
@override
@@ -224,15 +199,6 @@
lsp.ToJsonable message, T Function(Map<String, dynamic>) constructor) {
return constructor(jsonDecode(jsonEncode(message.toJson())));
}
-
- /// Checks whether a notification is likely an error from the server (for
- /// example a window/showMessage). This is useful for tests that want to
- /// ensure no errors come from the server in response to notifications (which
- /// don't have their own responses).
- bool _isErrorNotification(lsp.NotificationMessage notification) {
- return notification.method == Method.window_logMessage ||
- notification.method == Method.window_showMessage;
- }
}
/**