| // 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 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/dart/analysis/driver.dart'; |
| import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; |
| import 'package:analyzer_plugin/protocol/protocol.dart'; |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| import 'package:analyzer_plugin/protocol/protocol_generated.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'mocks.dart'; |
| |
| void main() { |
| defineReflectiveTests(ServerPluginTest); |
| } |
| |
| @reflectiveTest |
| class ServerPluginTest with ResourceProviderMixin { |
| late MockChannel channel; |
| late _TestServerPlugin plugin; |
| |
| late String packagePath1; |
| late String filePath1; |
| late ContextRoot contextRoot1; |
| |
| late String packagePath2; |
| late String filePath2; |
| late ContextRoot contextRoot2; |
| |
| void setUp() { |
| packagePath1 = convertPath('/package1'); |
| filePath1 = join(packagePath1, 'lib', 'test.dart'); |
| newFile(filePath1); |
| contextRoot1 = ContextRoot(packagePath1, <String>[]); |
| |
| packagePath2 = convertPath('/package2'); |
| filePath2 = join(packagePath2, 'lib', 'test.dart'); |
| newFile(filePath2); |
| contextRoot2 = ContextRoot(packagePath2, <String>[]); |
| |
| channel = MockChannel(); |
| plugin = _TestServerPlugin(resourceProvider); |
| plugin.start(channel); |
| } |
| |
| Future<void> test_contextRootContaining_insideRoot() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| expect(plugin.contextRootContaining(filePath1), isNotNull); |
| } |
| |
| void test_contextRootContaining_noRoots() { |
| expect(plugin.contextRootContaining(filePath1), isNull); |
| } |
| |
| Future<void> test_contextRootContaining_outsideRoot() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| expect(plugin.contextRootContaining(filePath2), isNull); |
| } |
| |
| Future<void> test_handleAnalysisGetNavigation() async { |
| var result = await plugin |
| .handleAnalysisGetNavigation(AnalysisGetNavigationParams('', 1, 2)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleAnalysisHandleWatchEvents() async { |
| var result = await plugin |
| .handleAnalysisHandleWatchEvents(AnalysisHandleWatchEventsParams([])); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleAnalysisSetContextRoots() async { |
| var result = await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| expect(result, isNotNull); |
| var driver = _getDriver(contextRoot1); |
| expect(driver, isNotNull); |
| expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); |
| } |
| |
| Future<void> test_handleAnalysisSetPriorityFiles() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin.handleAnalysisSetPriorityFiles( |
| AnalysisSetPriorityFilesParams([filePath1])); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleAnalysisSetSubscriptions() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), isEmpty); |
| |
| var result = await plugin |
| .handleAnalysisSetSubscriptions(AnalysisSetSubscriptionsParams({ |
| AnalysisService.OUTLINE: [filePath1] |
| })); |
| expect(result, isNotNull); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), |
| [AnalysisService.OUTLINE]); |
| } |
| |
| Future<void> test_handleAnalysisUpdateContent_addChangeRemove() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| var addResult = await plugin.handleAnalysisUpdateContent( |
| AnalysisUpdateContentParams( |
| {filePath1: AddContentOverlay('class C {}')})); |
| expect(addResult, isNotNull); |
| var changeResult = |
| await plugin.handleAnalysisUpdateContent(AnalysisUpdateContentParams({ |
| filePath1: ChangeContentOverlay([SourceEdit(7, 0, ' extends Object')]) |
| })); |
| expect(changeResult, isNotNull); |
| var removeResult = await plugin.handleAnalysisUpdateContent( |
| AnalysisUpdateContentParams({filePath1: RemoveContentOverlay()})); |
| expect(removeResult, isNotNull); |
| } |
| |
| Future<void> test_handleAnalysisUpdateContent_changeNoAdd() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| try { |
| await plugin.handleAnalysisUpdateContent(AnalysisUpdateContentParams({ |
| filePath1: ChangeContentOverlay([SourceEdit(7, 0, ' extends Object')]) |
| })); |
| fail('Expected RequestFailure'); |
| } on RequestFailure { |
| // Expected |
| } |
| } |
| |
| Future<void> test_handleAnalysisUpdateContent_invalidChange() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| await plugin.handleAnalysisUpdateContent(AnalysisUpdateContentParams( |
| {filePath1: AddContentOverlay('class C {}')})); |
| try { |
| await plugin.handleAnalysisUpdateContent(AnalysisUpdateContentParams({ |
| filePath1: ChangeContentOverlay([SourceEdit(20, 5, 'class D {}')]) |
| })); |
| fail('Expected RequestFailure'); |
| } on RequestFailure { |
| // Expected |
| } |
| } |
| |
| Future<void> test_handleCompletionGetSuggestions() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin.handleCompletionGetSuggestions( |
| CompletionGetSuggestionsParams(filePath1, 12)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleEditGetAssists() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin |
| .handleEditGetAssists(EditGetAssistsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleEditGetAvailableRefactorings() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin.handleEditGetAvailableRefactorings( |
| EditGetAvailableRefactoringsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handleEditGetFixes() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = |
| await plugin.handleEditGetFixes(EditGetFixesParams(filePath1, 13)); |
| expect(result, isNotNull); |
| } |
| |
| @failingTest |
| Future<void> test_handleEditGetRefactoring() async { |
| await plugin.handleAnalysisSetContextRoots( |
| AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin.handleEditGetRefactoring(EditGetRefactoringParams( |
| RefactoringKind.RENAME, filePath1, 7, 0, false)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handlePluginShutdown() async { |
| var result = await plugin.handlePluginShutdown(PluginShutdownParams()); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_handlePluginVersionCheck() async { |
| var result = await plugin.handlePluginVersionCheck( |
| PluginVersionCheckParams('byteStorePath', 'sdkPath', '0.1.0')); |
| expect(result, isNotNull); |
| expect(result.interestingFiles, ['*.dart']); |
| expect(result.isCompatible, isTrue); |
| expect(result.name, 'Test Plugin'); |
| expect(result.version, '0.1.0'); |
| } |
| |
| @failingTest |
| void test_isCompatibleWith() { |
| fail('Not yet implemented.'); |
| } |
| |
| void test_onDone() { |
| channel.sendDone(); |
| } |
| |
| void test_onError() { |
| channel.sendError(ArgumentError(), StackTrace.fromString('')); |
| } |
| |
| Future<void> test_onRequest_analysisGetNavigation() async { |
| var result = |
| await channel.sendRequest(AnalysisGetNavigationParams('', 1, 2)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_analysisHandleWatchEvents() async { |
| var result = await channel.sendRequest(AnalysisHandleWatchEventsParams([])); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_analysisSetContextRoots() async { |
| var result = await channel |
| .sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| expect(result, isNotNull); |
| var driver = _getDriver(contextRoot1); |
| expect(driver, isNotNull); |
| expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); |
| } |
| |
| Future<void> test_onRequest_analysisSetPriorityFiles() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = |
| await channel.sendRequest(AnalysisSetPriorityFilesParams([filePath1])); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_analysisSetSubscriptions() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), isEmpty); |
| |
| var result = await channel.sendRequest(AnalysisSetSubscriptionsParams({ |
| AnalysisService.OUTLINE: [filePath1] |
| })); |
| expect(result, isNotNull); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), |
| [AnalysisService.OUTLINE]); |
| } |
| |
| Future<void> test_onRequest_analysisUpdateContent_addChangeRemove() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| var addResult = await channel.sendRequest(AnalysisUpdateContentParams( |
| {filePath1: AddContentOverlay('class C {}')})); |
| expect(addResult, isNotNull); |
| var changeResult = await channel.sendRequest(AnalysisUpdateContentParams({ |
| filePath1: ChangeContentOverlay([SourceEdit(7, 0, ' extends Object')]) |
| })); |
| expect(changeResult, isNotNull); |
| var removeResult = await channel.sendRequest( |
| AnalysisUpdateContentParams({filePath1: RemoveContentOverlay()})); |
| expect(removeResult, isNotNull); |
| } |
| |
| Future<void> test_onRequest_completionGetSuggestions() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel |
| .sendRequest(CompletionGetSuggestionsParams(filePath1, 12)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_editGetAssists() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = |
| await channel.sendRequest(EditGetAssistsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_editGetAvailableRefactorings() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel |
| .sendRequest(EditGetAvailableRefactoringsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_editGetFixes() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel.sendRequest(EditGetFixesParams(filePath1, 13)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_editGetRefactoring() async { |
| await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel.sendRequest(EditGetRefactoringParams( |
| RefactoringKind.RENAME, filePath1, 7, 0, false)); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_pluginShutdown() async { |
| var result = await channel.sendRequest(PluginShutdownParams()); |
| expect(result, isNotNull); |
| } |
| |
| Future<void> test_onRequest_pluginVersionCheck() async { |
| var response = (await channel.sendRequest( |
| PluginVersionCheckParams('byteStorePath', 'sdkPath', '0.1.0'))); |
| var result = PluginVersionCheckResult.fromResponse(response); |
| expect(result, isNotNull); |
| expect(result.interestingFiles, ['*.dart']); |
| expect(result.isCompatible, isTrue); |
| expect(result.name, 'Test Plugin'); |
| expect(result.version, '0.1.0'); |
| } |
| |
| void test_sendNotificationsForFile() { |
| var service1 = AnalysisService.FOLDING; |
| var service2 = AnalysisService.NAVIGATION; |
| var service3 = AnalysisService.OUTLINE; |
| plugin.subscriptionManager.setSubscriptions({ |
| service1: [filePath1, filePath2], |
| service2: [filePath1], |
| service3: [filePath2] |
| }); |
| plugin.sendNotificationsForFile(filePath1); |
| var notifications = plugin.sentNotifications; |
| expect(notifications, hasLength(1)); |
| var services = notifications[filePath1]; |
| expect(services, unorderedEquals([service1, service2])); |
| } |
| |
| void test_sendNotificationsForSubscriptions() { |
| var subscriptions = <String, List<AnalysisService>>{}; |
| |
| plugin.sendNotificationsForSubscriptions(subscriptions); |
| var notifications = plugin.sentNotifications; |
| expect(notifications, hasLength(subscriptions.length)); |
| for (var path in subscriptions.keys) { |
| var subscribedServices = subscriptions[path]; |
| var notifiedServices = notifications[path]; |
| expect(notifiedServices, isNotNull, |
| reason: 'Not notified for file $path'); |
| expect(notifiedServices, unorderedEquals(subscribedServices!), |
| reason: 'Wrong notifications for file $path'); |
| } |
| } |
| |
| AnalysisDriverGeneric? _getDriver(ContextRoot targetRoot) { |
| for (var root in plugin.driverMap.keys) { |
| if (root.root == targetRoot.root) { |
| return plugin.driverMap[root]; |
| } |
| } |
| return null; |
| } |
| } |
| |
| class _TestServerPlugin extends MockServerPlugin { |
| Map<String, List<AnalysisService>> sentNotifications = |
| <String, List<AnalysisService>>{}; |
| |
| _TestServerPlugin(ResourceProvider resourceProvider) |
| : super(resourceProvider); |
| |
| @override |
| Future<void> sendFoldingNotification(String path) { |
| _sent(path, AnalysisService.FOLDING); |
| return Future.value(); |
| } |
| |
| @override |
| Future<void> sendHighlightsNotification(String path) { |
| _sent(path, AnalysisService.HIGHLIGHTS); |
| return Future.value(); |
| } |
| |
| @override |
| Future<void> sendNavigationNotification(String path) { |
| _sent(path, AnalysisService.NAVIGATION); |
| return Future.value(); |
| } |
| |
| @override |
| Future<void> sendOccurrencesNotification(String path) { |
| _sent(path, AnalysisService.OCCURRENCES); |
| return Future.value(); |
| } |
| |
| @override |
| Future<void> sendOutlineNotification(String path) { |
| _sent(path, AnalysisService.OUTLINE); |
| return Future.value(); |
| } |
| |
| void _sent(String path, AnalysisService service) { |
| sentNotifications.putIfAbsent(path, () => <AnalysisService>[]).add(service); |
| } |
| } |