Files
sdk/pkg/analyzer_plugin/test/plugin/mocks.dart
T
Sam Rawlins 895093e9f9 Initial PluginServer implementation
This is the core implementation of the "plugin server" that will support the API described at https://docs.google.com/document/d/1T8P323DJxsc3YPzveNIaSKWFkrJp9ydTR4jp_XFb7XQ/edit?resourcekey=0-f8Ue29KMUizqXNGhATp1tg#heading=h.23fjh5hfm2is

This is heavily curbed from the ServerPlugin class at
`package:analyzer_plugin/plugin/plugin.dart`, but does not depend on it.
It depends on two concepts from the analyzer_plugin package: (1) the
protocol used for de/serializing requests, responses, etc. And (2) the
`PluginCommunicationChannel` class. This is also just a utility for
communicating between the analysis server and the plugin server.

This plugin server is capable of "registering" individual "plugins",
which allows plugins to register individual (maybe multiple) lint rules,
and individual (maybe multiple) quick fixes.

The plugin server for now only responds essentially to three requests:

* `ANALYSIS_REQUEST_SET_CONTEXT_ROOTS`
* `EDIT_REQUEST_GET_FIXES`
* `PLUGIN_REQUEST_VERSION_CHECK`

All files are analyzed during `handleAnalysisSetContextRoots`, and
quick fixes are calculated during `handleEditGetFixes`.

There are many TODOs, but the included test shows that this plugin
server can notify the analysis server of lint diagnostics to be
reported, and can respond to a query for quick fixes.

Change-Id: Ibc93332319220a2caf49d20ab480940041a15049
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/382480
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
2024-08-29 16:03:42 +00:00

176 lines
4.5 KiB
Dart

// Copyright (c) 2017, 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:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/source/source.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
import 'package:test/test.dart';
class MockAnalysisDriver implements AnalysisDriver {
@override
final Set<String> addedFiles = {};
@override
set priorityFiles(List<String> priorityPaths) {}
@override
void addFile(String path) {
addedFiles.add(path);
}
@override
dynamic noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}
class MockChannel implements PluginCommunicationChannel {
bool _closed = false;
void Function()? _onDone;
Function? _onError;
void Function(Notification)? _onNotification;
void Function(Request)? _onRequest;
List<Notification> sentNotifications = <Notification>[];
int idCounter = 0;
Map<String, Completer<Response>> completers = <String, Completer<Response>>{};
@override
void close() {
_closed = true;
}
@override
void listen(void Function(Request request)? onRequest,
{void Function()? onDone,
Function? onError,
Function(Notification)? onNotification}) {
_onDone = onDone;
_onError = onError;
_onNotification = onNotification;
_onRequest = onRequest;
}
void sendDone() {
if (_onDone != null) {
_onDone!();
}
}
void sendError(Object exception, StackTrace stackTrace) {
if (_onError != null) {
_onError!(exception, stackTrace);
}
}
@override
void sendNotification(Notification notification) {
if (_closed) {
throw StateError('Sent a notification to a closed channel');
}
if (_onNotification == null) {
fail('Unexpected invocation of sendNotification');
}
_onNotification!(notification);
}
Future<Response> sendRequest(RequestParams params) {
if (_onRequest == null) {
fail('Unexpected invocation of sendNotification');
}
var id = (idCounter++).toString();
var request = params.toRequest(id);
var completer = Completer<Response>();
completers[request.id] = completer;
_onRequest!(request);
return completer.future;
}
@override
void sendResponse(Response response) {
if (_closed) {
throw StateError('Sent a response to a closed channel');
}
var completer = completers.remove(response.id);
completer?.complete(response);
}
}
class MockResolvedUnitResult implements ResolvedUnitResult {
@override
final List<AnalysisError> errors;
@override
final LineInfo lineInfo;
@override
final String path;
MockResolvedUnitResult(
{List<AnalysisError>? errors, LineInfo? lineInfo, String? path})
: errors = errors ?? [],
lineInfo = lineInfo ?? LineInfo([0]),
path = path ?? '';
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockResourceProvider implements ResourceProvider {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/// A concrete implementation of a server plugin that is suitable for testing.
class MockServerPlugin extends ServerPlugin {
MockServerPlugin(ResourceProvider resourceProvider)
: super(resourceProvider: resourceProvider);
@override
List<String> get fileGlobsToAnalyze => <String>['*.dart'];
@override
String get name => 'Test Plugin';
@override
String get version => '0.1.0';
@override
Future<void> analyzeFile({
required AnalysisContext analysisContext,
required String path,
}) async {}
}
class MockSource implements Source {
@override
TimestampedData<String> get contents => TimestampedData(0, '');
@override
String get fullName => '/pkg/lib/test.dart';
@override
String get shortName => 'test.dart';
@override
Uri get uri => Uri.parse('package:test/test.dart');
@override
bool exists() => true;
}