// 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/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 { MockChannel channel; _TestServerPlugin plugin; String packagePath1; String filePath1; ContextRoot contextRoot1; String packagePath2; String filePath2; ContextRoot contextRoot2; void setUp() { packagePath1 = convertPath('/package1'); filePath1 = join(packagePath1, 'lib', 'test.dart'); newFile(filePath1); contextRoot1 = ContextRoot(packagePath1, []); packagePath2 = convertPath('/package2'); filePath2 = join(packagePath2, 'lib', 'test.dart'); newFile(filePath2); contextRoot2 = ContextRoot(packagePath2, []); channel = MockChannel(); plugin = _TestServerPlugin(resourceProvider); plugin.start(channel); } Future test_contextRootContaining_insideRoot() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); expect(plugin.contextRootContaining(filePath1), isNotNull); } void test_contextRootContaining_noRoots() { expect(plugin.contextRootContaining(filePath1), isNull); } Future test_contextRootContaining_outsideRoot() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); expect(plugin.contextRootContaining(filePath2), isNull); } Future test_handleAnalysisGetNavigation() async { var result = await plugin .handleAnalysisGetNavigation(AnalysisGetNavigationParams('', 1, 2)); expect(result, isNotNull); } Future test_handleAnalysisHandleWatchEvents() async { var result = await plugin .handleAnalysisHandleWatchEvents(AnalysisHandleWatchEventsParams([])); expect(result, isNotNull); } Future test_handleAnalysisSetContextRoots() async { var result = await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); expect(result, isNotNull); AnalysisDriverGeneric driver = _getDriver(contextRoot1); expect(driver, isNotNull); expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); } Future test_handleAnalysisSetPriorityFiles() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); var result = await plugin.handleAnalysisSetPriorityFiles( AnalysisSetPriorityFilesParams([filePath1])); expect(result, isNotNull); } Future test_handleAnalysisSetSubscriptions() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); expect(plugin.subscriptionManager.servicesForFile(filePath1), isEmpty); AnalysisSetSubscriptionsResult result = await plugin .handleAnalysisSetSubscriptions(AnalysisSetSubscriptionsParams({ AnalysisService.OUTLINE: [filePath1] })); expect(result, isNotNull); expect(plugin.subscriptionManager.servicesForFile(filePath1), [AnalysisService.OUTLINE]); } Future 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 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 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 test_handleCompletionGetSuggestions() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); CompletionGetSuggestionsResult result = await plugin.handleCompletionGetSuggestions( CompletionGetSuggestionsParams(filePath1, 12)); expect(result, isNotNull); } Future test_handleEditGetAssists() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); EditGetAssistsResult result = await plugin .handleEditGetAssists(EditGetAssistsParams(filePath1, 10, 0)); expect(result, isNotNull); } Future test_handleEditGetAvailableRefactorings() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); EditGetAvailableRefactoringsResult result = await plugin.handleEditGetAvailableRefactorings( EditGetAvailableRefactoringsParams(filePath1, 10, 0)); expect(result, isNotNull); } Future test_handleEditGetFixes() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); EditGetFixesResult result = await plugin.handleEditGetFixes(EditGetFixesParams(filePath1, 13)); expect(result, isNotNull); } @failingTest Future test_handleEditGetRefactoring() async { await plugin.handleAnalysisSetContextRoots( AnalysisSetContextRootsParams([contextRoot1])); EditGetRefactoringResult result = await plugin.handleEditGetRefactoring( EditGetRefactoringParams( RefactoringKind.RENAME, filePath1, 7, 0, false)); expect(result, isNotNull); } Future test_handlePluginShutdown() async { var result = await plugin.handlePluginShutdown(PluginShutdownParams()); expect(result, isNotNull); } Future test_handlePluginVersionCheck() async { PluginVersionCheckResult 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 test_onRequest_analysisGetNavigation() async { var result = await channel.sendRequest(AnalysisGetNavigationParams('', 1, 2)); expect(result, isNotNull); } Future test_onRequest_analysisHandleWatchEvents() async { var result = await channel.sendRequest(AnalysisHandleWatchEventsParams([])); expect(result, isNotNull); } Future test_onRequest_analysisSetContextRoots() async { var result = await channel .sendRequest(AnalysisSetContextRootsParams([contextRoot1])); expect(result, isNotNull); AnalysisDriverGeneric driver = _getDriver(contextRoot1); expect(driver, isNotNull); expect((driver as MockAnalysisDriver).addedFiles, hasLength(1)); } Future test_onRequest_analysisSetPriorityFiles() async { await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); var result = await channel.sendRequest(AnalysisSetPriorityFilesParams([filePath1])); expect(result, isNotNull); } Future 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 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 test_onRequest_completionGetSuggestions() async { await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); var result = await channel .sendRequest(CompletionGetSuggestionsParams(filePath1, 12)); expect(result, isNotNull); } Future test_onRequest_editGetAssists() async { await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); var result = await channel.sendRequest(EditGetAssistsParams(filePath1, 10, 0)); expect(result, isNotNull); } Future test_onRequest_editGetAvailableRefactorings() async { await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); var result = await channel .sendRequest(EditGetAvailableRefactoringsParams(filePath1, 10, 0)); expect(result, isNotNull); } Future test_onRequest_editGetFixes() async { await channel.sendRequest(AnalysisSetContextRootsParams([contextRoot1])); var result = await channel.sendRequest(EditGetFixesParams(filePath1, 13)); expect(result, isNotNull); } Future 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 test_onRequest_pluginShutdown() async { var result = await channel.sendRequest(PluginShutdownParams()); expect(result, isNotNull); } Future test_onRequest_pluginVersionCheck() async { var response = (await channel.sendRequest( PluginVersionCheckParams('byteStorePath', 'sdkPath', '0.1.0'))); PluginVersionCheckResult 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() { 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> notifications = plugin.sentNotifications; expect(notifications, hasLength(1)); List services = notifications[filePath1]; expect(services, unorderedEquals([service1, service2])); } void test_sendNotificationsForSubscriptions() { Map> subscriptions = >{}; plugin.sendNotificationsForSubscriptions(subscriptions); Map> notifications = plugin.sentNotifications; expect(notifications, hasLength(subscriptions.length)); for (String path in subscriptions.keys) { List subscribedServices = subscriptions[path]; List 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> sentNotifications = >{}; _TestServerPlugin(ResourceProvider resourceProvider) : super(resourceProvider); @override Future sendFoldingNotification(String path) { _sent(path, AnalysisService.FOLDING); return Future.value(); } @override Future sendHighlightsNotification(String path) { _sent(path, AnalysisService.HIGHLIGHTS); return Future.value(); } @override Future sendNavigationNotification(String path) { _sent(path, AnalysisService.NAVIGATION); return Future.value(); } @override Future sendOccurrencesNotification(String path) { _sent(path, AnalysisService.OCCURRENCES); return Future.value(); } @override Future sendOutlineNotification(String path) { _sent(path, AnalysisService.OUTLINE); return Future.value(); } void _sent(String path, AnalysisService service) { sentNotifications.putIfAbsent(path, () => []).add(service); } }