mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 15:17:07 +00:00
Change setup of capabilities in LSP tests to allow easier chaining
Change-Id: I6bc2743d64e7eb263f34f9c12140588d35b1482e Reviewed-on: https://dart-review.googlesource.com/c/87065 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
83c6f7695d
commit
7d4a6cc7e3
7 changed files with 312 additions and 232 deletions
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) 2018, 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 'package:analysis_server/lsp_protocol/protocol_generated.dart';
|
||||
|
||||
import 'server_abstract.dart';
|
||||
|
||||
abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest {
|
||||
initializeWithSupportForKinds(List<CodeActionKind> kinds) async {
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'codeAction': {
|
||||
'codeActionLiteralSupport': {
|
||||
'codeActionKind': {
|
||||
'valueSet': kinds.map((k) => k.toJson()).toList(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import 'package:test/test.dart';
|
|||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../tool/lsp_spec/matchers.dart';
|
||||
import 'code_actions_abstract.dart';
|
||||
import 'server_abstract.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
|
@ -18,8 +18,69 @@ main() {
|
|||
});
|
||||
}
|
||||
|
||||
abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest {
|
||||
Future<void> checkCodeActionAvailable(
|
||||
Uri uri,
|
||||
String command,
|
||||
String title, {
|
||||
bool asCodeActionLiteral = false,
|
||||
bool asCommand = false,
|
||||
}) async {
|
||||
final codeActions = await getCodeActions(uri.toString());
|
||||
final codeAction = findCommand(codeActions, command);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
codeAction.map(
|
||||
(command) {
|
||||
if (!asCommand) {
|
||||
throw 'Got Command but expected CodeAction literal';
|
||||
}
|
||||
expect(command.title, equals(title));
|
||||
expect(command.arguments, equals([uri.toFilePath()]));
|
||||
},
|
||||
(codeAction) {
|
||||
if (!asCodeActionLiteral) {
|
||||
throw 'Got CodeAction literal but expected Command';
|
||||
}
|
||||
expect(codeAction, isNotNull);
|
||||
expect(codeAction.title, equals(title));
|
||||
expect(codeAction.command.title, equals(title));
|
||||
expect(codeAction.command.arguments, equals([uri.toFilePath()]));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Either2<Command, CodeAction> findCommand(
|
||||
List<Either2<Command, CodeAction>> actions, String commandID) {
|
||||
for (var codeAction in actions) {
|
||||
final id = codeAction.map(
|
||||
(cmd) => cmd.command, (action) => action.command.command);
|
||||
if (id == commandID) {
|
||||
return codeAction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
CodeAction findEditAction(List<Either2<Command, CodeAction>> actions,
|
||||
CodeActionKind actionKind, String title) {
|
||||
for (var codeAction in actions) {
|
||||
final codeActionLiteral =
|
||||
codeAction.map((cmd) => null, (action) => action);
|
||||
if (codeActionLiteral?.kind == actionKind &&
|
||||
codeActionLiteral?.title == title) {
|
||||
// We're specifically looking for an action that contains an edit.
|
||||
assert(codeActionLiteral.command == null);
|
||||
assert(codeActionLiteral.edit != null);
|
||||
return codeActionLiteral;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class OrganizeImportsSourceCodeActionsTest extends SourceCodeActionsTest {
|
||||
class OrganizeImportsSourceCodeActionsTest extends AbstractCodeActionsTest {
|
||||
test_appliesCorrectEdits_withDocumentChangesSupport() async {
|
||||
const content = '''
|
||||
import 'dart:math';
|
||||
|
@ -37,10 +98,12 @@ Future foo;
|
|||
int minified(int x, int y) => min(x, y);
|
||||
''';
|
||||
await newFile(mainFilePath, content: content);
|
||||
await initializeWithDocumentChangesSupport();
|
||||
await initialize(
|
||||
workspaceCapabilities:
|
||||
withDocumentChangesSupport(emptyWorkspaceClientCapabilities));
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.organizeImports);
|
||||
final codeAction = findCommand(codeActions, Commands.organizeImports);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -97,7 +160,7 @@ int minified(int x, int y) => min(x, y);
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.organizeImports);
|
||||
final codeAction = findCommand(codeActions, Commands.organizeImports);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -136,7 +199,10 @@ int minified(int x, int y) => min(x, y);
|
|||
|
||||
test_availableAsCodeActionLiteral() async {
|
||||
await newFile(mainFilePath);
|
||||
await initializeWithSupportForKinds([CodeActionKind.Source]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCodeActionKinds(
|
||||
emptyTextDocumentClientCapabilities, [CodeActionKind.Source]),
|
||||
);
|
||||
|
||||
await checkCodeActionAvailable(
|
||||
mainFileUri,
|
||||
|
@ -164,7 +230,7 @@ int minified(int x, int y) => min(x, y);
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.organizeImports);
|
||||
final codeAction = findCommand(codeActions, Commands.organizeImports);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -190,7 +256,7 @@ int minified(int x, int y) => min(x, y);
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.organizeImports);
|
||||
final codeAction = findCommand(codeActions, Commands.organizeImports);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -207,16 +273,19 @@ int minified(int x, int y) => min(x, y);
|
|||
|
||||
test_unavailableWhenNotRequested() async {
|
||||
await newFile(mainFilePath);
|
||||
await initializeWithSupportForKinds([CodeActionKind.Refactor]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCodeActionKinds(
|
||||
emptyTextDocumentClientCapabilities, [CodeActionKind.Refactor]),
|
||||
);
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.organizeImports);
|
||||
final codeAction = findCommand(codeActions, Commands.organizeImports);
|
||||
expect(codeAction, isNull);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
||||
class SortMembersSourceCodeActionsTest extends AbstractCodeActionsTest {
|
||||
test_appliesCorrectEdits_withDocumentChangesSupport() async {
|
||||
const content = '''
|
||||
String b;
|
||||
|
@ -227,10 +296,12 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
String b;
|
||||
''';
|
||||
await newFile(mainFilePath, content: content);
|
||||
await initializeWithDocumentChangesSupport();
|
||||
await initialize(
|
||||
workspaceCapabilities:
|
||||
withDocumentChangesSupport(emptyWorkspaceClientCapabilities));
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.sortMembers);
|
||||
final codeAction = findCommand(codeActions, Commands.sortMembers);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -280,7 +351,7 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.sortMembers);
|
||||
final codeAction = findCommand(codeActions, Commands.sortMembers);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -319,7 +390,10 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
|
||||
test_availableAsCodeActionLiteral() async {
|
||||
await newFile(mainFilePath);
|
||||
await initializeWithSupportForKinds([CodeActionKind.Source]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCodeActionKinds(
|
||||
emptyTextDocumentClientCapabilities, [CodeActionKind.Source]),
|
||||
);
|
||||
|
||||
await checkCodeActionAvailable(
|
||||
mainFileUri,
|
||||
|
@ -350,7 +424,7 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.sortMembers);
|
||||
final codeAction = findCommand(codeActions, Commands.sortMembers);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -380,7 +454,7 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
await initialize();
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.sortMembers);
|
||||
final codeAction = findCommand(codeActions, Commands.sortMembers);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
final command = codeAction.map(
|
||||
|
@ -396,63 +470,13 @@ class SortMembersSourceCodeActionsTest extends SourceCodeActionsTest {
|
|||
|
||||
test_unavailableWhenNotRequested() async {
|
||||
await newFile(mainFilePath);
|
||||
await initializeWithSupportForKinds([CodeActionKind.Refactor]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCodeActionKinds(
|
||||
emptyTextDocumentClientCapabilities, [CodeActionKind.Refactor]),
|
||||
);
|
||||
|
||||
final codeActions = await getCodeActions(mainFileUri.toString());
|
||||
final codeAction = _findCommand(codeActions, Commands.sortMembers);
|
||||
final codeAction = findCommand(codeActions, Commands.sortMembers);
|
||||
expect(codeAction, isNull);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SourceCodeActionsTest extends AbstractCodeActionsTest {
|
||||
Future<void> checkCodeActionAvailable(
|
||||
Uri uri,
|
||||
String command,
|
||||
String title, {
|
||||
bool asCodeActionLiteral = false,
|
||||
bool asCommand = false,
|
||||
}) async {
|
||||
final codeActions = await getCodeActions(uri.toString());
|
||||
final codeAction = _findCommand(codeActions, command);
|
||||
expect(codeAction, isNotNull);
|
||||
|
||||
codeAction.map(
|
||||
(command) {
|
||||
if (!asCommand) {
|
||||
throw 'Got Command but expected CodeAction literal';
|
||||
}
|
||||
expect(command.title, equals(title));
|
||||
expect(command.arguments, equals([uri.toFilePath()]));
|
||||
},
|
||||
(codeAction) {
|
||||
if (!asCodeActionLiteral) {
|
||||
throw 'Got CodeAction literal but expected Command';
|
||||
}
|
||||
expect(codeAction, isNotNull);
|
||||
expect(codeAction.title, equals(title));
|
||||
expect(codeAction.command.title, equals(title));
|
||||
expect(codeAction.command.arguments, equals([uri.toFilePath()]));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initializeWithDocumentChangesSupport() async {
|
||||
await initialize(workspaceCapabilities: {
|
||||
'workspaceEdit': {
|
||||
'documentChanges': true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Either2<Command, CodeAction> _findCommand(
|
||||
List<Either2<Command, CodeAction>> actions, String commandID) {
|
||||
for (var codeAction in actions) {
|
||||
final id = codeAction.map(
|
||||
(cmd) => cmd.command, (action) => action.command.command);
|
||||
if (id == commandID) {
|
||||
return codeAction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,17 +40,16 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
final content = "import '^';";
|
||||
|
||||
// Tell the server we support some specific CompletionItemKinds.
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'completion': {
|
||||
'completionItemKind': {
|
||||
'valueSet': [
|
||||
CompletionItemKind.File.toJson(),
|
||||
CompletionItemKind.Folder.toJson(),
|
||||
CompletionItemKind.Module.toJson(),
|
||||
],
|
||||
}
|
||||
},
|
||||
});
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCompletionItemKinds(
|
||||
emptyTextDocumentClientCapabilities,
|
||||
[
|
||||
CompletionItemKind.File,
|
||||
CompletionItemKind.Folder,
|
||||
CompletionItemKind.Module,
|
||||
],
|
||||
),
|
||||
);
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
|
||||
|
@ -75,15 +74,10 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
''';
|
||||
|
||||
// Tell the server we only support the Field CompletionItemKind.
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'completion': {
|
||||
'completionItemKind': {
|
||||
'valueSet': [
|
||||
CompletionItemKind.Field.toJson(),
|
||||
],
|
||||
}
|
||||
},
|
||||
});
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCompletionItemKinds(
|
||||
emptyTextDocumentClientCapabilities, [CompletionItemKind.Field]),
|
||||
);
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
final kinds = res.map((item) => item.kind).toList();
|
||||
|
@ -171,13 +165,9 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
}
|
||||
''';
|
||||
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'completion': {
|
||||
'completionItem': {
|
||||
'deprecatedSupport': true,
|
||||
}
|
||||
},
|
||||
});
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCompletionItemDeprecatedSupport(
|
||||
emptyTextDocumentClientCapabilities));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
final item = res.singleWhere((c) => c.label == 'abcdefghij');
|
||||
|
@ -223,13 +213,9 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
}
|
||||
''';
|
||||
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'completion': {
|
||||
'completionItem': {
|
||||
'snippetSupport': true,
|
||||
}
|
||||
}
|
||||
});
|
||||
await initialize(
|
||||
textDocumentCapabilities: withCompletionItemSnippetSupport(
|
||||
emptyTextDocumentClientCapabilities));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
expect(res.any((c) => c.label == 'abcdefghij'), isTrue);
|
||||
|
|
|
@ -26,11 +26,9 @@ class DocumentSymbolsTest extends AbstractLspAnalysisServerTest {
|
|||
}
|
||||
''';
|
||||
newFile(mainFilePath, content: content);
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'documentSymbol': {
|
||||
'hierarchicalDocumentSymbolSupport': true,
|
||||
},
|
||||
});
|
||||
await initialize(
|
||||
textDocumentCapabilities: withHierarchicalDocumentSymbolSupport(
|
||||
emptyTextDocumentClientCapabilities));
|
||||
|
||||
final result = await getDocumentSymbols(mainFileUri.toString());
|
||||
final symbols = result.map(
|
||||
|
|
|
@ -18,14 +18,6 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class HoverTest extends AbstractLspAnalysisServerTest {
|
||||
Future<void> initializeSupportingMarkupContent([
|
||||
List<MarkupKind> formats = const [MarkupKind.Markdown],
|
||||
]) async {
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'hover': {'contentFormat': formats.map((f) => f.toJson())}
|
||||
});
|
||||
}
|
||||
|
||||
test_hover_bad_position() async {
|
||||
await initialize();
|
||||
await openFile(mainFileUri, '');
|
||||
|
@ -66,7 +58,9 @@ print();
|
|||
'''
|
||||
.trim();
|
||||
|
||||
await initializeSupportingMarkupContent([MarkupKind.Markdown]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withHoverContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final hover = await getHover(mainFileUri, positionFromMarker(content));
|
||||
expect(hover, isNotNull);
|
||||
|
@ -83,7 +77,9 @@ print();
|
|||
String [[a^bc]];
|
||||
''';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withHoverContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final hover = await getHover(mainFileUri, positionFromMarker(content));
|
||||
expect(hover, isNotNull);
|
||||
|
@ -103,7 +99,9 @@ print();
|
|||
int a;
|
||||
''';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withHoverContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
var hover = await getHover(mainFileUri, positionFromMarker(content));
|
||||
expect(hover, isNull);
|
||||
|
@ -115,7 +113,9 @@ print();
|
|||
String [[a^bc]];
|
||||
''';
|
||||
|
||||
await initializeSupportingMarkupContent([MarkupKind.PlainText]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withHoverContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.PlainText]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final hover = await getHover(mainFileUri, positionFromMarker(content));
|
||||
expect(hover, isNotNull);
|
||||
|
|
|
@ -27,7 +27,8 @@ const debugPrintCommunication = false;
|
|||
|
||||
final beginningOfDocument = new Range(new Position(0, 0), new Position(0, 0));
|
||||
|
||||
abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
||||
abstract class AbstractLspAnalysisServerTest
|
||||
with ResourceProviderMixin, ClientCapabilitiesHelperMixin {
|
||||
static const positionMarker = '^';
|
||||
static const rangeMarkerStart = '[[';
|
||||
static const rangeMarkerEnd = ']]';
|
||||
|
@ -42,31 +43,15 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
String projectFolderPath, mainFilePath;
|
||||
Uri mainFileUri;
|
||||
|
||||
final emptyTextDocumentClientCapabilities =
|
||||
new TextDocumentClientCapabilities(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
final emptyWorkspaceClientCapabilities = new WorkspaceClientCapabilities(
|
||||
null, null, null, null, null, null, null, null);
|
||||
void applyChanges(
|
||||
Map<String, String> fileContents,
|
||||
Map<String, List<TextEdit>> changes,
|
||||
) {
|
||||
changes.forEach((fileUri, edits) {
|
||||
final path = Uri.parse(fileUri).toFilePath();
|
||||
fileContents[path] = applyTextEdits(fileContents[path], edits);
|
||||
});
|
||||
}
|
||||
|
||||
void applyDocumentChanges(
|
||||
Map<String, String> fileContents,
|
||||
|
@ -82,16 +67,6 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
);
|
||||
}
|
||||
|
||||
void applyChanges(
|
||||
Map<String, String> fileContents,
|
||||
Map<String, List<TextEdit>> changes,
|
||||
) {
|
||||
changes.forEach((fileUri, edits) {
|
||||
final path = Uri.parse(fileUri).toFilePath();
|
||||
fileContents[path] = applyTextEdits(fileContents[path], edits);
|
||||
});
|
||||
}
|
||||
|
||||
void applyResourceChanges(
|
||||
Map<String, String> oldFileContent,
|
||||
List<Either4<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>> changes,
|
||||
|
@ -387,14 +362,10 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
/// match the spec exactly and are not verified.
|
||||
Future<ResponseMessage> initialize({
|
||||
String rootPath,
|
||||
Map<String, dynamic> textDocumentCapabilities,
|
||||
Map<String, dynamic> workspaceCapabilities,
|
||||
TextDocumentClientCapabilities textDocumentCapabilities,
|
||||
WorkspaceClientCapabilities workspaceCapabilities,
|
||||
}) async {
|
||||
final rootUri = Uri.file(rootPath ?? projectFolderPath).toString();
|
||||
final newTextDocumentCapabilities =
|
||||
overrideTextDocumentCapabilities(textDocumentCapabilities);
|
||||
final newWorkspaceCapabilities =
|
||||
overrideWorkspaceCapabilities(workspaceCapabilities);
|
||||
final request = makeRequest(
|
||||
Method.initialize,
|
||||
new InitializeParams(
|
||||
|
@ -403,8 +374,8 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
rootUri,
|
||||
null,
|
||||
new ClientCapabilities(
|
||||
newWorkspaceCapabilities,
|
||||
newTextDocumentCapabilities,
|
||||
workspaceCapabilities,
|
||||
textDocumentCapabilities,
|
||||
null,
|
||||
),
|
||||
null,
|
||||
|
@ -439,28 +410,6 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
await pumpEventQueue();
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities overrideTextDocumentCapabilities(
|
||||
Map<String, dynamic> textDocumentCapabilities) {
|
||||
final json = emptyTextDocumentClientCapabilities.toJson();
|
||||
if (textDocumentCapabilities != null) {
|
||||
textDocumentCapabilities.keys.forEach((key) {
|
||||
json[key] = textDocumentCapabilities[key];
|
||||
});
|
||||
}
|
||||
return TextDocumentClientCapabilities.fromJson(json);
|
||||
}
|
||||
|
||||
WorkspaceClientCapabilities overrideWorkspaceCapabilities(
|
||||
Map<String, dynamic> workspaceCapabilities) {
|
||||
final json = emptyWorkspaceClientCapabilities.toJson();
|
||||
if (workspaceCapabilities != null) {
|
||||
workspaceCapabilities.keys.forEach((key) {
|
||||
json[key] = workspaceCapabilities[key];
|
||||
});
|
||||
}
|
||||
return WorkspaceClientCapabilities.fromJson(json);
|
||||
}
|
||||
|
||||
Position positionFromMarker(String contents) =>
|
||||
positionFromOffset(contents.indexOf('^'), contents);
|
||||
|
||||
|
@ -548,3 +497,141 @@ abstract class AbstractLspAnalysisServerTest with ResourceProviderMixin {
|
|||
String withoutMarkers(String contents) =>
|
||||
contents.replaceAll(allMarkersPattern, '');
|
||||
}
|
||||
|
||||
mixin ClientCapabilitiesHelperMixin {
|
||||
final emptyTextDocumentClientCapabilities =
|
||||
new TextDocumentClientCapabilities(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
final emptyWorkspaceClientCapabilities = new WorkspaceClientCapabilities(
|
||||
null, null, null, null, null, null, null, null);
|
||||
|
||||
TextDocumentClientCapabilities extendTextDocumentCapabilities(
|
||||
TextDocumentClientCapabilities source,
|
||||
Map<String, dynamic> textDocumentCapabilities,
|
||||
) {
|
||||
final json = source.toJson();
|
||||
if (textDocumentCapabilities != null) {
|
||||
textDocumentCapabilities.keys.forEach((key) {
|
||||
json[key] = textDocumentCapabilities[key];
|
||||
});
|
||||
}
|
||||
return TextDocumentClientCapabilities.fromJson(json);
|
||||
}
|
||||
|
||||
WorkspaceClientCapabilities extendWorkspaceCapabilities(
|
||||
WorkspaceClientCapabilities source,
|
||||
Map<String, dynamic> workspaceCapabilities,
|
||||
) {
|
||||
final json = source.toJson();
|
||||
if (workspaceCapabilities != null) {
|
||||
workspaceCapabilities.keys.forEach((key) {
|
||||
json[key] = workspaceCapabilities[key];
|
||||
});
|
||||
}
|
||||
return WorkspaceClientCapabilities.fromJson(json);
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withCodeActionKinds(
|
||||
TextDocumentClientCapabilities source,
|
||||
List<CodeActionKind> kinds,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'codeAction': {
|
||||
'codeActionLiteralSupport': {
|
||||
'codeActionKind': {'valueSet': kinds.map((k) => k.toJson()).toList()}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withCompletionItemDeprecatedSupport(
|
||||
TextDocumentClientCapabilities source,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'completion': {
|
||||
'completionItem': {'deprecatedSupport': true}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withCompletionItemSnippetSupport(
|
||||
TextDocumentClientCapabilities source,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'completion': {
|
||||
'completionItem': {'snippetSupport': true}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withCompletionItemKinds(
|
||||
TextDocumentClientCapabilities source,
|
||||
List<CompletionItemKind> kinds,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'completion': {
|
||||
'completionItemKind': {
|
||||
'valueSet': kinds.map((k) => k.toJson()).toList()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withHoverContentFormat(
|
||||
TextDocumentClientCapabilities source,
|
||||
List<MarkupKind> formats,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'hover': {'contentFormat': formats.map((k) => k.toJson()).toList()}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withSignatureHelpContentFormat(
|
||||
TextDocumentClientCapabilities source,
|
||||
List<MarkupKind> formats,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'signatureHelp': {
|
||||
'signatureInformation': {
|
||||
'documentationFormat': formats.map((k) => k.toJson()).toList()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TextDocumentClientCapabilities withHierarchicalDocumentSymbolSupport(
|
||||
TextDocumentClientCapabilities source,
|
||||
) {
|
||||
return extendTextDocumentCapabilities(source, {
|
||||
'documentSymbol': {'hierarchicalDocumentSymbolSupport': true}
|
||||
});
|
||||
}
|
||||
|
||||
WorkspaceClientCapabilities withDocumentChangesSupport(
|
||||
WorkspaceClientCapabilities source,
|
||||
) {
|
||||
return extendWorkspaceCapabilities(source, {
|
||||
'workspaceEdit': {'documentChanges': true}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,18 +16,6 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
||||
Future<void> initializeSupportingMarkupContent([
|
||||
List<MarkupKind> formats = const [MarkupKind.Markdown],
|
||||
]) async {
|
||||
await initialize(textDocumentCapabilities: {
|
||||
'signatureHelp': {
|
||||
'signatureInformation': {
|
||||
'documentationFormat': formats.map((f) => f.toJson())
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test_formats_markdown() async {
|
||||
final content = '''
|
||||
/// Does foo.
|
||||
|
@ -38,7 +26,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, int i)';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent([MarkupKind.Markdown]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -86,7 +76,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, int i)';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent([MarkupKind.PlainText]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.PlainText]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -113,8 +105,10 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
// We say we prefer PlainText as a client, but since we only really
|
||||
// support Markdown and the client supports it, we expect the server
|
||||
// to provide Markdown.
|
||||
await initializeSupportingMarkupContent(
|
||||
[MarkupKind.PlainText, MarkupKind.Markdown]);
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities,
|
||||
[MarkupKind.PlainText, MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -139,7 +133,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, {bool b = true, bool a})';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -164,7 +160,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, [bool b = true, bool a])';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -189,7 +187,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, {bool b = true})';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -213,7 +213,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, [bool b = true])';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -236,7 +238,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedLabel = 'foo(String s, int i)';
|
||||
final expectedDoc = 'Does foo.';
|
||||
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
await testSignature(
|
||||
content,
|
||||
|
@ -260,7 +264,9 @@ class SignatureHelpTest extends AbstractLspAnalysisServerTest {
|
|||
final expectedDoc = 'Does foo.';
|
||||
|
||||
newFile(mainFilePath, content: withoutMarkers(content));
|
||||
await initializeSupportingMarkupContent();
|
||||
await initialize(
|
||||
textDocumentCapabilities: withSignatureHelpContentFormat(
|
||||
emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
|
||||
await testSignature(
|
||||
content,
|
||||
expectedLabel,
|
||||
|
|
Loading…
Reference in a new issue