| // Copyright (c) 2014, 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. |
| |
| library test.domain.analysis.abstract; |
| |
| import 'dart:async'; |
| |
| import 'package:analysis_server/src/analysis_server.dart'; |
| import 'package:analysis_server/src/domain_analysis.dart'; |
| import 'package:analysis_server/src/constants.dart'; |
| import 'package:analysis_server/src/protocol.dart'; |
| import 'package:analysis_server/src/resource.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:unittest/unittest.dart'; |
| |
| import 'mocks.dart'; |
| |
| |
| main() { |
| } |
| |
| |
| /** |
| * An abstract base for all 'analysis' domain tests. |
| */ |
| class AbstractAnalysisTest { |
| MockServerChannel serverChannel; |
| MemoryResourceProvider resourceProvider; |
| AnalysisServer server; |
| AnalysisDomainHandler handler; |
| |
| Map<String, List<String>> analysisSubscriptions = {}; |
| |
| String projectPath = '/project'; |
| String testFile = '/project/bin/test.dart'; |
| String testCode; |
| |
| // Map<String, List<AnalysisError>> filesErrors = {}; |
| // Map<String, List<Map<String, Object>>> filesHighlights = {}; |
| // Map<String, List<Map<String, Object>>> filesNavigation = {}; |
| |
| |
| AbstractAnalysisTest() { |
| } |
| |
| void setUp() { |
| serverChannel = new MockServerChannel(); |
| resourceProvider = new MemoryResourceProvider(); |
| server = new AnalysisServer(serverChannel, resourceProvider); |
| handler = new AnalysisDomainHandler(server); |
| // listen for notifications |
| Stream<Notification> notificationStream = serverChannel.notificationController.stream; |
| notificationStream.listen((Notification notification) { |
| processNotification(notification); |
| }); |
| // create an empty project |
| _createEmptyProject(); |
| } |
| |
| void addAnalysisSubscription(AnalysisService service, String file) { |
| // add file to subscription |
| var files = analysisSubscriptions[service.name]; |
| if (files == null) { |
| files = <String>[]; |
| analysisSubscriptions[service.name] = files; |
| } |
| files.add(file); |
| // set subscriptions |
| Request request = new Request('0', METHOD_SET_ANALYSIS_SUBSCRIPTIONS); |
| request.setParameter(SUBSCRIPTIONS, analysisSubscriptions); |
| handleSuccessfulRequest(request); |
| } |
| |
| void tearDown() { |
| server.done(); |
| handler = null; |
| server = null; |
| resourceProvider = null; |
| serverChannel = null; |
| } |
| |
| void processNotification(Notification notification) { |
| // if (notification.event == NOTIFICATION_ERRORS) { |
| // String file = notification.getParameter(FILE); |
| // List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS); |
| // filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList(); |
| // } |
| // if (notification.event == NOTIFICATION_HIGHLIGHTS) { |
| // String file = notification.getParameter(FILE); |
| // filesHighlights[file] = notification.getParameter(REGIONS); |
| // } |
| // if (notification.event == NOTIFICATION_NAVIGATION) { |
| // String file = notification.getParameter(FILE); |
| // filesNavigation[file] = notification.getParameter(REGIONS); |
| // } |
| } |
| |
| /** |
| * Returns a [Future] that completes when the [AnalysisServer] finishes |
| * all its scheduled tasks. |
| */ |
| Future waitForTasksFinished() { |
| return waitForServerOperationsPerformed(server); |
| } |
| |
| /** |
| * Returns the offset of [search] in [testCode]. |
| * Fails if not found. |
| */ |
| int findFileOffset(String path, String search) { |
| File file = resourceProvider.getResource(path) as File; |
| String code = file.createSource(UriKind.FILE_URI).contents.data; |
| int offset = code.indexOf(search); |
| expect(offset, isNot(-1), reason: '"$search" in\n$code'); |
| return offset; |
| } |
| |
| /** |
| * Returns the offset of [search] in [testCode]. |
| * Fails if not found. |
| */ |
| int findOffset(String search) { |
| int offset = testCode.indexOf(search); |
| expect(offset, isNot(-1)); |
| return offset; |
| } |
| |
| // /** |
| // * Returns [AnalysisError]s recorded for the given [file]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<AnalysisError> getErrors(String file) { |
| // List<AnalysisError> errors = filesErrors[file]; |
| // if (errors != null) { |
| // return errors; |
| // } |
| // return <AnalysisError>[]; |
| // } |
| // |
| // /** |
| // * Returns highlights recorded for the given [file]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<Map<String, Object>> getHighlights(String file) { |
| // List<Map<String, Object>> highlights = filesHighlights[file]; |
| // if (highlights != null) { |
| // return highlights; |
| // } |
| // return []; |
| // } |
| // |
| // /** |
| // * Returns navigation regions recorded for the given [file]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<Map<String, Object>> getNavigation(String file) { |
| // List<Map<String, Object>> navigation = filesNavigation[file]; |
| // if (navigation != null) { |
| // return navigation; |
| // } |
| // return []; |
| // } |
| // |
| // /** |
| // * Returns [AnalysisError]s recorded for the [testFile]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<AnalysisError> getTestErrors() { |
| // return getErrors(testFile); |
| // } |
| // |
| // /** |
| // * Returns highlights recorded for the given [testFile]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<Map<String, Object>> getTestHighlights() { |
| // return getHighlights(testFile); |
| // } |
| // |
| // /** |
| // * Returns navigation information recorded for the given [testFile]. |
| // * May be empty, but not `null`. |
| // */ |
| // List<Map<String, Object>> getTestNavigation() { |
| // return getNavigation(testFile); |
| // } |
| |
| /** |
| * Creates an empty project `/project/`. |
| */ |
| void _createEmptyProject() { |
| resourceProvider.newFolder(projectPath); |
| Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS); |
| request.setParameter(INCLUDED, [projectPath]); |
| request.setParameter(EXCLUDED, []); |
| handleSuccessfulRequest(request); |
| } |
| |
| // /** |
| // * Creates a project with a single Dart file `/project/bin/test.dart` with |
| // * the given [code]. |
| // */ |
| // void createSingleFileProject(code) { |
| // this.testCode = _getCodeString(code); |
| // resourceProvider.newFolder('/project'); |
| // resourceProvider.newFile(testFile, testCode); |
| // Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS); |
| // request.setParameter(INCLUDED, ['/project']); |
| // request.setParameter(EXCLUDED, []); |
| // handleSuccessfulRequest(request); |
| // } |
| |
| String addFile(String path, String content) { |
| resourceProvider.newFile(path, content); |
| return path; |
| } |
| |
| String addTestFile(String content) { |
| addFile(testFile, content); |
| this.testCode = content; |
| return testFile; |
| } |
| |
| /** |
| * Validates that the given [request] is handled successfully. |
| */ |
| void handleSuccessfulRequest(Request request) { |
| Response response = handler.handleRequest(request); |
| expect(response, isResponseSuccess('0')); |
| } |
| |
| static String _getCodeString(code) { |
| if (code is List<String>) { |
| code = code.join('\n'); |
| } |
| return code as String; |
| } |
| } |
| |
| |
| |
| class AnalysisError { |
| final String file; |
| final String errorCode; |
| final int offset; |
| final int length; |
| final String message; |
| final String correction; |
| AnalysisError(this.file, this.errorCode, this.offset, this.length, |
| this.message, this.correction); |
| |
| @override |
| String toString() { |
| return 'NotificationError(file=$file; errorCode=$errorCode; ' |
| 'offset=$offset; length=$length; message=$message)'; |
| } |
| } |
| |
| |
| AnalysisError _jsonToAnalysisError(Map<String, Object> json) { |
| return new AnalysisError( |
| json['file'], |
| json['errorCode'], |
| json['offset'], |
| json['length'], |
| json['message'], |
| json['correction']); |
| } |
| |
| |
| int findIdentifierLength(String search) { |
| int length = 0; |
| while (length < search.length) { |
| int c = search.codeUnitAt(length); |
| if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) || |
| c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) || |
| c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) { |
| break; |
| } |
| length++; |
| } |
| return length; |
| } |