// 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 'package:analysis_server/protocol/protocol.dart'; import 'package:analysis_server/protocol/protocol_generated.dart' hide AnalysisOptions; import 'package:analysis_server/src/analysis_server.dart'; import 'package:analysis_server/src/domain_analysis.dart'; import 'package:analysis_server/src/domain_completion.dart'; import 'package:analysis_server/src/server/crash_reporting_attachments.dart'; import 'package:analysis_server/src/utilities/mocks.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:analyzer/instrumentation/instrumentation.dart'; import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:analyzer/src/generated/engine.dart'; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/test_utilities/mock_sdk.dart'; import 'package:matcher/matcher.dart'; import 'package:meta/meta.dart'; import '../../mocks.dart'; abstract class AbstractClient { final MockServerChannel serverChannel; final TestPluginManager pluginManager; late AnalysisServer server; final List generalServices = []; final Map> analysisSubscriptions = {}; final String projectPath; final String testFilePath; late String testCode; late MockSdk sdk; final AnalysisServerOptions serverOptions; AbstractClient({ required this.projectPath, required this.testFilePath, required String sdkPath, required this.serverOptions, }) : serverChannel = MockServerChannel(), pluginManager = TestPluginManager() { server = createAnalysisServer(sdkPath); var notificationStream = serverChannel.notificationController.stream; notificationStream.listen((Notification notification) { processNotification(notification); }); } AnalysisDomainHandler get analysisHandler => server.handlers.singleWhere((handler) => handler is AnalysisDomainHandler) as AnalysisDomainHandler; AnalysisOptions get analysisOptions => testDriver.analysisOptions; CompletionDomainHandler get completionHandler => server.handlers.whereType().single; MemoryResourceProvider get resourceProvider; AnalysisDriver get testDriver => server.getAnalysisDriver(testFilePath)!; void addAnalysisOptionsFile(String content) { newFile( resourceProvider.pathContext.join(projectPath, 'analysis_options.yaml'), content); } void addAnalysisSubscription(AnalysisService service, String file) { // add file to subscription var files = analysisSubscriptions[service]; if (files == null) { files = []; analysisSubscriptions[service] = files; } files.add(file); // set subscriptions var request = AnalysisSetSubscriptionsParams(analysisSubscriptions).toRequest('0'); handleSuccessfulRequest(request); } void addGeneralAnalysisSubscription(GeneralAnalysisService service) { generalServices.add(service); var request = AnalysisSetGeneralSubscriptionsParams(generalServices).toRequest('0'); handleSuccessfulRequest(request); } String addTestFile(String content) { newFile(testFilePath, content); testCode = content; return testFilePath; } void assertValidId(String id) { expect(id, isNotNull); expect(id.isNotEmpty, isTrue); } /// Create an analysis server with the given [sdkPath]. AnalysisServer createAnalysisServer(String sdkPath) { sdk = MockSdk(resourceProvider: resourceProvider); return AnalysisServer( serverChannel, resourceProvider, serverOptions, DartSdkManager(sdkPath), CrashReportingAttachmentsBuilder.empty, InstrumentationService.NULL_SERVICE); } /// Create a project at [projectPath]. @mustCallSuper void createProject({Map? packageRoots}) { newFolder(projectPath); var request = AnalysisSetAnalysisRootsParams([projectPath], [], packageRoots: packageRoots) .toRequest('0'); handleSuccessfulRequest(request, handler: analysisHandler); } void expect(actual, matcher, {String reason}); /// Validate that the given [request] is handled successfully. Response handleSuccessfulRequest(Request request, {RequestHandler? handler}) { handler ??= analysisHandler; var response = handler.handleRequest(request)!; expect(response, isResponseSuccess(request.id)); return response; } File newFile(String path, String content, [int stamp]); Folder newFolder(String path); void processNotification(Notification notification); /// Returns a [Future] that completes when the server's analysis is complete. Future waitForTasksFinished() => server.onAnalysisComplete; /// Completes with a successful [Response] for the given [request]. /// Otherwise fails. Future waitResponse(Request request, {bool throwOnError = true}) async { return serverChannel.sendRequest(request, throwOnError: throwOnError); } }