blob: 6b725cb7f81bf915e1b4733153c6b460bc843123 [file] [log] [blame]
// Copyright (c) 2020, 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 AnalysisOptions;
import 'package:analyzer/src/test_utilities/test_code_format.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
import '../../analysis_server_base.dart';
import 'expect_mixin.dart';
class CompletionDriver with ExpectMixin {
final PubPackageAnalysisServerTest server;
Map<String, Completer<void>> receivedSuggestionsCompleters = {};
List<CompletionSuggestion> suggestions = [];
Map<String, List<CompletionSuggestion>> allSuggestions = {};
final Map<String, ExistingImports> fileToExistingImports = {};
final Map<String, List<AnalysisError>> filesErrors = {};
late String completionId;
late int completionOffset;
late int replacementOffset;
late int replacementLength;
CompletionDriver({required this.server}) {
server.serverChannel.notifications.listen(processNotification);
}
void addTestFile(String content, {int? offset}) {
var code = TestCode.parse(content);
if (offset != null) {
expect(code.positions, isEmpty, reason: 'cannot supply offset and ^');
completionOffset = offset;
} else {
completionOffset = code.position.offset;
}
server.newFile(server.testFilePath, code.code);
}
void assertValidId(String id) {
expect(id, isNotNull);
expect(id.isNotEmpty, isTrue);
}
Future<void> createProject() async {
await server.setRoots(included: [server.workspaceRootPath], excluded: []);
}
Future<List<CompletionSuggestion>> getSuggestions() async {
var request = CompletionGetSuggestions2Params(
server.convertPath(server.testFilePath),
completionOffset,
1 << 16,
timeout: 60 * 1000,
).toRequest('0', clientUriConverter: null);
var response = await server.handleRequest(request);
if (response.error case var error?) {
fail('${request.method} failed: ${error.code}: ${error.message}');
}
var result = CompletionGetSuggestions2Result.fromResponse(
response,
clientUriConverter: null,
);
replacementOffset = result.replacementOffset;
replacementLength = result.replacementLength;
return result.suggestions;
}
@mustCallSuper
Future<void> processNotification(Notification notification) async {
if (notification.event == COMPLETION_NOTIFICATION_EXISTING_IMPORTS) {
var params = CompletionExistingImportsParams.fromNotification(
notification,
clientUriConverter: null,
);
fileToExistingImports[params.file] = params.imports;
} else if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
var decoded = AnalysisErrorsParams.fromNotification(
notification,
clientUriConverter: null,
);
filesErrors[decoded.file] = decoded.errors;
} else if (notification.event == ANALYSIS_NOTIFICATION_FLUSH_RESULTS) {
// Ignored.
} else if (notification.event == SERVER_NOTIFICATION_ERROR) {
throw Exception('server error: ${notification.toJson()}');
} else if (notification.event == SERVER_NOTIFICATION_CONNECTED) {
// Ignored.
} else {
print('Unhandled notification: ${notification.event}');
}
}
}