blob: fccd17e88040a565d42df96778b639c36dced619 [file] [log] [blame]
// 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 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
hide MessageType;
import 'package:analysis_server/src/analysis_server.dart' show MessageType;
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'analysis_server_base.dart';
import 'constants.dart';
import 'mocks.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ServerDomainTest);
defineReflectiveTests(ServerDartFixPromptTest);
});
}
/// Checks server interacts with [DartFixPromptManager] correctly.
///
/// Tests for [DartFixPromptManager]'s behaviour are in
/// test/services/user_prompts/dart_fix_prompt_manager_test.dart.
@reflectiveTest
class ServerDartFixPromptTest extends PubPackageAnalysisServerTest {
late TestDartFixPromptManager promptManager;
@override
DartFixPromptManager? get dartFixPromptManager => promptManager;
@override
void setUp() {
promptManager = TestDartFixPromptManager();
super.setUp();
}
Future<void> test_trigger_afterInitialAnalysis() async {
await setRoots(included: [workspaceRootPath], excluded: []);
await pumpEventQueue(times: 5000);
expect(promptManager.checksTriggered, 1);
}
Future<void> test_trigger_afterPackageConfigChange() async {
// Ensure there's a file to analyze otherwise writing the package_config
// won't trigger any additional analysis.
newFile('$testPackageLibPath/test.dart', 'void f() {}');
// Set up and let initial analysis complete.
await setRoots(included: [workspaceRootPath], excluded: []);
await pumpEventQueue(times: 5000);
expect(promptManager.checksTriggered, 1);
// Expect that writing package config attempts to trigger another check.
writeTestPackageConfig();
await pumpEventQueue(times: 5000);
expect(promptManager.checksTriggered, 2);
}
}
@reflectiveTest
class ServerDomainTest extends PubPackageAnalysisServerTest {
Future<void> test_getVersion() async {
var request = ServerGetVersionParams().toRequest('0');
var response = await handleSuccessfulRequest(request);
expect(
response.toJson(),
equals({
Response.ID: '0',
Response.RESULT: {VERSION: PROTOCOL_VERSION}
}));
}
Future<void> test_openUrl() async {
server.clientCapabilities.requests = ['openUrlRequest'];
// Send the request.
var uri = toUri('https://dart.dev');
var responseFuture = server.openUriNotificationSender!.call(uri);
expect(serverChannel.serverRequestsSent, hasLength(1));
// Simulate the response.
var request = serverChannel.serverRequestsSent[0];
await serverChannel.simulateResponseFromClient(
ServerOpenUrlRequestResult().toResponse(request.id));
await responseFuture;
}
Future<void> test_setClientCapabilities_requests() async {
var requestId = -1;
Future<void> setCapabilities(
{required bool openUrlRequest,
required bool showMessageRequest}) async {
var requests = [
if (openUrlRequest) 'openUrlRequest',
if (showMessageRequest) 'showMessageRequest',
];
if (requestId >= 0) {
// This is a bit of a kludge, but the first time this function is called
// we won't set the request, we'll just test the default state.
var request = ServerSetClientCapabilitiesParams(requests)
.toRequest(requestId.toString());
await handleSuccessfulRequest(request);
}
requestId++;
expect(server.clientCapabilities.requests, requests);
expect(server.openUriNotificationSender,
openUrlRequest ? isNotNull : isNull);
expect(server.userPromptSender, showMessageRequest ? isNotNull : isNull);
}
await setCapabilities(openUrlRequest: false, showMessageRequest: false);
await setCapabilities(openUrlRequest: true, showMessageRequest: false);
await setCapabilities(openUrlRequest: true, showMessageRequest: true);
await setCapabilities(openUrlRequest: false, showMessageRequest: true);
await setCapabilities(openUrlRequest: false, showMessageRequest: false);
}
/// Verify that the server handles URIs once we've enabled the supportsUris
/// client capability.
Future<void>
test_setClientCapabilities_supportsUris_clientToServer_request() async {
// Tell the server we support URIs.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([], supportsUris: true)
.toRequest('-1'));
// Set the roots using a URI. Since the helper methods will to through
// toJson() (which will convert paths to URIs) we need to pass the JSON
// manually here.
await handleSuccessfulRequest(Request('1', 'analysis.setAnalysisRoots', {
'included': [toUri(workspaceRootPath).toString()],
'excluded': [],
}));
await pumpEventQueue(times: 5000);
// Ensure the roots were recorded correctly.
expect(
server.contextManager.includedPaths,
[convertPath(workspaceRootPath)],
);
}
Future<void> test_setClientCapabilities_supportsUris_defaults() async {
// Before request.
expect(server.clientCapabilities.supportsUris, isNull);
expect(server.uriConverter.supportedNonFileSchemes, isEmpty);
// If not supplied.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([]).toRequest('-1'));
expect(server.clientCapabilities.supportsUris, isNull);
expect(server.uriConverter.supportedNonFileSchemes, isEmpty);
// If set explicitly to false.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([], supportsUris: false)
.toRequest('-1'));
expect(server.clientCapabilities.supportsUris, isFalse);
expect(server.uriConverter.supportedNonFileSchemes, isEmpty);
}
Future<void>
test_setClientCapabilities_supportsUris_false_rejectsUris() async {
// Explicitly tell the server we do not support URIs.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([], supportsUris: false)
.toRequest('-1'));
// Try to send a URI anyway.
var request = Request('1', 'analysis.setAnalysisRoots', {
'included': [toUri(workspaceRootPath).toString()],
'excluded': [],
});
var response = await handleRequest(request);
expect(
response,
isResponseFailure(
request.id, RequestErrorCode.INVALID_FILE_PATH_FORMAT));
}
/// Verify that the server uses URIs in notifications once we've enabled the
/// supportsUris client capability.
Future<void>
test_setClientCapabilities_supportsUris_serverToClient_notification() async {
// Add a file with an error for testing.
var testFilePath = convertPath('$testPackageLibPath/test.dart');
var testFileUriString = toUri(testFilePath).toString();
newFile(testFilePath, 'broken');
// Tell the server we support URIs before analysis starts since we will
// verify the analysis.errors notification.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([], supportsUris: true)
.toRequest('10'));
await pumpEventQueue(times: 5000);
// Trigger analysis.
await setRoots(
// We can use paths here because toJson() will handle the conversion.
included: [workspaceRootPath],
excluded: [],
);
await pumpEventQueue(times: 5000);
// Verify the last error for this file was using a URI.
var lastErrorFile = serverChannel.notificationsReceived
.where((notification) => notification.event == 'analysis.errors')
.map((notification) => notification.params!['file'] as String)
.lastWhere((filePath) => filePath.endsWith('test.dart'));
expect(
lastErrorFile,
testFileUriString,
);
}
/// Verify that the server returns URIs once we've enabled the supportsUris
/// client capability.
Future<void>
test_setClientCapabilities_supportsUris_serverToClient_response() async {
// Add a file with an error for testing.
var testFilePath = convertPath('$testPackageLibPath/test.dart');
var testFileUriString = toUri(testFilePath).toString();
newFile(testFilePath, 'broken');
await setRoots(included: [workspaceRootPath], excluded: []);
await pumpEventQueue(times: 5000);
// Tell the server we support URIs.
await handleSuccessfulRequest(
ServerSetClientCapabilitiesParams([], supportsUris: true)
.toRequest('10'));
await pumpEventQueue(times: 5000);
// Send a GetErrors request. The response has nested FilePaths inside the
// AnalysisErrors so will confirm the server mapped correctly.
var response =
await handleSuccessfulRequest(Request('1', 'analysis.getErrors', {
'file': testFileUriString,
}));
// Verify the error location was the expected URI.
expect(
(response.result as dynamic)['errors'][0]!['location']['file'],
testFileUriString,
);
}
Future<void>
test_setClientCapabilities_supportsUris_unspecified_rejectsUris() async {
// Do not tell the server we support URIs.
// Try to send a URI anyway.
var request = Request('1', 'analysis.setAnalysisRoots', {
'included': [toUri(workspaceRootPath).toString()],
'excluded': [],
});
var response = await handleRequest(request);
expect(
response,
isResponseFailure(
request.id, RequestErrorCode.INVALID_FILE_PATH_FORMAT));
}
Future<void> test_setSubscriptions_invalidServiceName() async {
var request = Request('0', SERVER_REQUEST_SET_SUBSCRIPTIONS, {
SUBSCRIPTIONS: ['noSuchService']
});
var response = await handleRequest(request);
expect(response, isResponseFailure('0'));
}
Future<void> test_setSubscriptions_success() async {
expect(server.serverServices, isEmpty);
// send request
var request =
ServerSetSubscriptionsParams([ServerService.STATUS]).toRequest('0');
await handleSuccessfulRequest(request);
// set of services has been changed
expect(server.serverServices, contains(ServerService.STATUS));
}
Future<void> test_showMessage() async {
server.clientCapabilities.requests = ['showMessageRequest'];
// Send the request.
var responseFuture =
server.userPromptSender!(MessageType.warning, 'message', ['a', 'b']);
expect(serverChannel.serverRequestsSent, hasLength(1));
// Simulate the response.
var request = serverChannel.serverRequestsSent[0];
await serverChannel.simulateResponseFromClient(
ServerShowMessageRequestResult(action: 'a').toResponse(request.id));
var response = await responseFuture;
expect(response, 'a');
}
Future<void> test_showMessage_nullResponse() async {
server.clientCapabilities.requests = ['showMessageRequest'];
// Send the request.
var responseFuture =
server.userPromptSender!(MessageType.warning, 'message', ['a', 'b']);
expect(serverChannel.serverRequestsSent, hasLength(1));
// Simulate the response.
var request = serverChannel.serverRequestsSent[0];
await serverChannel.simulateResponseFromClient(
ServerShowMessageRequestResult().toResponse(request.id));
var response = await responseFuture;
expect(response, isNull);
}
Future<void> test_shutdown() async {
var request = ServerShutdownParams().toRequest('0');
await handleSuccessfulRequest(request);
}
}
class TestDartFixPromptManager implements DartFixPromptManager {
var checksTriggered = 0;
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
void triggerCheck() {
checksTriggered++;
}
}