blob: e691b0e9d182c59004c2dbbe16dd5be60441f777 [file] [log] [blame]
// Copyright (c) 2023, 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 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analyzer/src/test_utilities/test_code_format.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../test/tool/lsp_spec/matchers.dart';
import '../../test/utils/test_code_extensions.dart';
import '../support/integration_tests.dart';
import 'abstract_lsp_over_legacy.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(LspOverLegacyRequestTest);
});
}
/// Integration tests for sending LSP requests over the Legacy protocol.
///
/// These tests are slow (each test spawns an out-of-process server) so these
/// tests are intended only to ensure the basic functionality is available and
/// not to test all handlers/functionality already covered by LSP tests.
///
/// Additional tests (to verify each expected LSP handler is available over
/// Legacy) are in `test/lsp_over_legacy/` and tests for all handler
/// functionality are in `test/lsp`.
@reflectiveTest
class LspOverLegacyRequestTest extends AbstractLspOverLegacyTest {
Future<void> test_error_invalidLspRequest() async {
await standardAnalysisSetup();
await analysisFinished;
try {
await sendLspHandle({'id': '1'});
fail('expected INVALID_PARAMETER');
} on ServerErrorMessage catch (message) {
expect(message.error['code'], 'INVALID_PARAMETER');
expect(
message.error['message'],
"The 'lspMessage' parameter was not a valid LSP request:\n"
'jsonrpc must not be undefined',
);
}
}
Future<void> test_error_lspHandlerError() async {
// testFile will not be created.
await standardAnalysisSetup();
await analysisFinished;
await expectLater(
getHover(testFileUri, Position(character: 0, line: 0)),
throwsA(
isResponseError(
ServerErrorCodes.InvalidFilePath,
message: 'File does not exist',
),
),
);
}
Future<void> test_format() async {
const content = 'void main() {}';
const expectedContent = 'void main() {}';
writeFile(testFile, content);
await standardAnalysisSetup();
await analysisFinished;
var edits = await formatDocument(testFileUri);
var formattedContents = applyTextEdits(content, edits!);
expect(formattedContents.trimRight(), equals(expectedContent));
}
Future<void> test_hover() async {
var code = TestCode.parse('''
/// This is my class.
class [!A^aa!] {}
''');
writeFile(testFile, code.code);
await standardAnalysisSetup();
await analysisFinished;
var result = await getHover(testFileUri, code.position.position);
expect(result!.range, code.range.range);
expectMarkdown(result.contents, '''
```dart
class Aaa
```
Declared in _package:test/main.dart_.
---
This is my class.
''');
}
/// Tests the protocol using JSON instead of helpers.
///
/// This is to verify (and document) the exact payloads for `lsp.handle`
/// in a way that is not abstracted by (or affected by refactors to) helper
/// methods to ensure this never changes in a way that will affect clients.
Future<void> test_hover_rawProtocol() async {
var code = TestCode.parse('''
/// This is my class.
class [!A^aa!] {}
''');
const expectedHover = '''
```dart
class Aaa
```
Declared in _package:test/main.dart_.
---
This is my class.''';
writeFile(testFile, code.code);
await standardAnalysisSetup();
await analysisFinished;
var response = await server.send('lsp.handle', {
'lspMessage': {
'jsonrpc': '2.0',
'id': '12345',
'method': Method.textDocument_hover.toString(),
'params': {
'textDocument': {'uri': testFileUri.toString()},
'position': code.position.position.toJson(),
},
},
});
expect(response, {
'lspResponse': {
'id': '12345',
'jsonrpc': '2.0',
'result': {
'contents': {'kind': 'markdown', 'value': expectedHover},
'range': code.range.range.toJson(),
},
},
});
}
}