| // 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/file_system/file_system.dart'; |
| import 'package:analyzer/file_system/memory_file_system.dart'; |
| import 'package:analyzer/src/dart/analysis/driver.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:path/src/context.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 { |
| MemoryResourceProvider resourceProvider = new MemoryResourceProvider(); |
| |
| MockChannel channel; |
| _TestServerPlugin plugin; |
| |
| String packagePath1; |
| String filePath1; |
| ContextRoot contextRoot1; |
| |
| String packagePath2; |
| String filePath2; |
| ContextRoot contextRoot2; |
| |
| void setUp() { |
| Context pathContext = resourceProvider.pathContext; |
| |
| packagePath1 = resourceProvider.convertPath('/package1'); |
| filePath1 = pathContext.join(packagePath1, 'lib', 'test.dart'); |
| resourceProvider.newFile(filePath1, ''); |
| contextRoot1 = new ContextRoot(packagePath1, <String>[]); |
| |
| packagePath2 = resourceProvider.convertPath('/package2'); |
| filePath2 = pathContext.join(packagePath2, 'lib', 'test.dart'); |
| resourceProvider.newFile(filePath2, ''); |
| contextRoot2 = new ContextRoot(packagePath2, <String>[]); |
| |
| channel = new MockChannel(); |
| plugin = new _TestServerPlugin(resourceProvider); |
| plugin.start(channel); |
| } |
| |
| test_contextRootContaining_insideRoot() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| expect(plugin.contextRootContaining(filePath1), isNotNull); |
| } |
| |
| void test_contextRootContaining_noRoots() { |
| expect(plugin.contextRootContaining(filePath1), isNull); |
| } |
| |
| test_contextRootContaining_outsideRoot() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| expect(plugin.contextRootContaining(filePath2), isNull); |
| } |
| |
| test_handleAnalysisGetNavigation() async { |
| var result = await plugin |
| .handleAnalysisGetNavigation(new AnalysisGetNavigationParams('', 1, 2)); |
| expect(result, isNotNull); |
| } |
| |
| test_handleAnalysisHandleWatchEvents() async { |
| var result = await plugin.handleAnalysisHandleWatchEvents( |
| new AnalysisHandleWatchEventsParams([])); |
| expect(result, isNotNull); |
| } |
| |
| test_handleAnalysisSetContextRoots() async { |
| var result = await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| expect(result, isNotNull); |
| AnalysisDriverGeneric driver = _getDriver(contextRoot1); |
| expect(driver, isNotNull); |
| expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); |
| } |
| |
| test_handleAnalysisSetPriorityFiles() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await plugin.handleAnalysisSetPriorityFiles( |
| new AnalysisSetPriorityFilesParams([filePath1])); |
| expect(result, isNotNull); |
| } |
| |
| test_handleAnalysisSetSubscriptions() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), isEmpty); |
| |
| AnalysisSetSubscriptionsResult result = await plugin |
| .handleAnalysisSetSubscriptions(new AnalysisSetSubscriptionsParams({ |
| AnalysisService.OUTLINE: [filePath1] |
| })); |
| expect(result, isNotNull); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), |
| [AnalysisService.OUTLINE]); |
| } |
| |
| test_handleAnalysisUpdateContent_addChangeRemove() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| var addResult = await plugin.handleAnalysisUpdateContent( |
| new AnalysisUpdateContentParams( |
| {filePath1: new AddContentOverlay('class C {}')})); |
| expect(addResult, isNotNull); |
| var changeResult = await plugin |
| .handleAnalysisUpdateContent(new AnalysisUpdateContentParams({ |
| filePath1: |
| new ChangeContentOverlay([new SourceEdit(7, 0, ' extends Object')]) |
| })); |
| expect(changeResult, isNotNull); |
| var removeResult = await plugin.handleAnalysisUpdateContent( |
| new AnalysisUpdateContentParams( |
| {filePath1: new RemoveContentOverlay()})); |
| expect(removeResult, isNotNull); |
| } |
| |
| test_handleAnalysisUpdateContent_changeNoAdd() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| try { |
| await plugin.handleAnalysisUpdateContent(new AnalysisUpdateContentParams({ |
| filePath1: |
| new ChangeContentOverlay([new SourceEdit(7, 0, ' extends Object')]) |
| })); |
| fail('Expected RequestFailure'); |
| } on RequestFailure { |
| // Expected |
| } |
| } |
| |
| test_handleAnalysisUpdateContent_invalidChange() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| await plugin.handleAnalysisUpdateContent(new AnalysisUpdateContentParams( |
| {filePath1: new AddContentOverlay('class C {}')})); |
| try { |
| await plugin.handleAnalysisUpdateContent(new AnalysisUpdateContentParams({ |
| filePath1: |
| new ChangeContentOverlay([new SourceEdit(20, 5, 'class D {}')]) |
| })); |
| fail('Expected RequestFailure'); |
| } on RequestFailure { |
| // Expected |
| } |
| } |
| |
| test_handleCompletionGetSuggestions() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| CompletionGetSuggestionsResult result = |
| await plugin.handleCompletionGetSuggestions( |
| new CompletionGetSuggestionsParams(filePath1, 12)); |
| expect(result, isNotNull); |
| } |
| |
| test_handleEditGetAssists() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| EditGetAssistsResult result = await plugin |
| .handleEditGetAssists(new EditGetAssistsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| test_handleEditGetAvailableRefactorings() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| EditGetAvailableRefactoringsResult result = |
| await plugin.handleEditGetAvailableRefactorings( |
| new EditGetAvailableRefactoringsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| test_handleEditGetFixes() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| EditGetFixesResult result = |
| await plugin.handleEditGetFixes(new EditGetFixesParams(filePath1, 13)); |
| expect(result, isNotNull); |
| } |
| |
| @failingTest |
| test_handleEditGetRefactoring() async { |
| await plugin.handleAnalysisSetContextRoots( |
| new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| EditGetRefactoringResult result = await plugin.handleEditGetRefactoring( |
| new EditGetRefactoringParams( |
| RefactoringKind.RENAME, filePath1, 7, 0, false)); |
| expect(result, isNotNull); |
| } |
| |
| test_handlePluginShutdown() async { |
| var result = await plugin.handlePluginShutdown(new PluginShutdownParams()); |
| expect(result, isNotNull); |
| } |
| |
| test_handlePluginVersionCheck() async { |
| PluginVersionCheckResult result = await plugin.handlePluginVersionCheck( |
| new 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(new ArgumentError(), new StackTrace.fromString('')); |
| } |
| |
| test_onRequest_analysisGetNavigation() async { |
| var result = |
| await channel.sendRequest(new AnalysisGetNavigationParams('', 1, 2)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_analysisHandleWatchEvents() async { |
| var result = |
| await channel.sendRequest(new AnalysisHandleWatchEventsParams([])); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_analysisSetContextRoots() async { |
| var result = await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| expect(result, isNotNull); |
| AnalysisDriverGeneric driver = _getDriver(contextRoot1); |
| expect(driver, isNotNull); |
| expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); |
| } |
| |
| test_onRequest_analysisSetPriorityFiles() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel |
| .sendRequest(new AnalysisSetPriorityFilesParams([filePath1])); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_analysisSetSubscriptions() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), isEmpty); |
| |
| var result = await channel.sendRequest(new AnalysisSetSubscriptionsParams({ |
| AnalysisService.OUTLINE: [filePath1] |
| })); |
| expect(result, isNotNull); |
| expect(plugin.subscriptionManager.servicesForFile(filePath1), |
| [AnalysisService.OUTLINE]); |
| } |
| |
| test_onRequest_analysisUpdateContent_addChangeRemove() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| var addResult = await channel.sendRequest(new AnalysisUpdateContentParams( |
| {filePath1: new AddContentOverlay('class C {}')})); |
| expect(addResult, isNotNull); |
| var changeResult = |
| await channel.sendRequest(new AnalysisUpdateContentParams({ |
| filePath1: |
| new ChangeContentOverlay([new SourceEdit(7, 0, ' extends Object')]) |
| })); |
| expect(changeResult, isNotNull); |
| var removeResult = await channel.sendRequest( |
| new AnalysisUpdateContentParams( |
| {filePath1: new RemoveContentOverlay()})); |
| expect(removeResult, isNotNull); |
| } |
| |
| test_onRequest_completionGetSuggestions() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel |
| .sendRequest(new CompletionGetSuggestionsParams(filePath1, 12)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_editGetAssists() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = |
| await channel.sendRequest(new EditGetAssistsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_editGetAvailableRefactorings() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel |
| .sendRequest(new EditGetAvailableRefactoringsParams(filePath1, 10, 0)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_editGetFixes() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = |
| await channel.sendRequest(new EditGetFixesParams(filePath1, 13)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_editGetRefactoring() async { |
| await channel |
| .sendRequest(new AnalysisSetContextRootsParams([contextRoot1])); |
| |
| var result = await channel.sendRequest(new EditGetRefactoringParams( |
| RefactoringKind.RENAME, filePath1, 7, 0, false)); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_pluginShutdown() async { |
| var result = await channel.sendRequest(new PluginShutdownParams()); |
| expect(result, isNotNull); |
| } |
| |
| test_onRequest_pluginVersionCheck() async { |
| var response = (await channel.sendRequest( |
| new PluginVersionCheckParams('byteStorePath', 'sdkPath', '0.1.0'))); |
| PluginVersionCheckResult result = |
| new 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'); |
| } |
| |
| test_sendNotificationsForFile() { |
| AnalysisService service1 = AnalysisService.FOLDING; |
| AnalysisService service2 = AnalysisService.NAVIGATION; |
| AnalysisService service3 = AnalysisService.OUTLINE; |
| plugin.subscriptionManager.setSubscriptions({ |
| service1: [filePath1, filePath2], |
| service2: [filePath1], |
| service3: [filePath2] |
| }); |
| plugin.sendNotificationsForFile(filePath1); |
| Map<String, List<AnalysisService>> notifications = plugin.sentNotifications; |
| expect(notifications, hasLength(1)); |
| List<AnalysisService> services = notifications[filePath1]; |
| expect(services, unorderedEquals([service1, service2])); |
| } |
| |
| test_sendNotificationsForSubscriptions() { |
| Map<String, List<AnalysisService>> subscriptions = |
| <String, List<AnalysisService>>{}; |
| |
| plugin.sendNotificationsForSubscriptions(subscriptions); |
| Map<String, List<AnalysisService>> notifications = plugin.sentNotifications; |
| expect(notifications, hasLength(subscriptions.length)); |
| for (String path in subscriptions.keys) { |
| List<AnalysisService> subscribedServices = subscriptions[path]; |
| List<AnalysisService> 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 (ContextRoot 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 new Future.value(); |
| } |
| |
| @override |
| Future<void> sendHighlightsNotification(String path) { |
| _sent(path, AnalysisService.HIGHLIGHTS); |
| return new Future.value(); |
| } |
| |
| @override |
| Future<void> sendNavigationNotification(String path) { |
| _sent(path, AnalysisService.NAVIGATION); |
| return new Future.value(); |
| } |
| |
| @override |
| Future<void> sendOccurrencesNotification(String path) { |
| _sent(path, AnalysisService.OCCURRENCES); |
| return new Future.value(); |
| } |
| |
| @override |
| Future<void> sendOutlineNotification(String path) { |
| _sent(path, AnalysisService.OUTLINE); |
| return new Future.value(); |
| } |
| |
| void _sent(String path, AnalysisService service) { |
| sentNotifications.putIfAbsent(path, () => <AnalysisService>[]).add(service); |
| } |
| } |