| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library test.domain.analysis.abstract; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'package:analysis_server/src/analysis_server.dart'; |
| 10 import 'package:analysis_server/src/domain_analysis.dart'; |
| 11 import 'package:analysis_server/src/constants.dart'; |
| 12 import 'package:analysis_server/src/protocol.dart'; |
| 13 import 'package:analysis_server/src/resource.dart'; |
| 14 import 'package:analyzer/src/generated/source.dart'; |
| 15 import 'package:unittest/unittest.dart'; |
| 16 |
| 17 import 'mocks.dart'; |
| 18 |
| 19 |
| 20 /** |
| 21 * An abstract base for all 'analysis' domain tests. |
| 22 */ |
| 23 class AbstractAnalysisTest { |
| 24 MockServerChannel serverChannel; |
| 25 MemoryResourceProvider resourceProvider; |
| 26 AnalysisServer server; |
| 27 AnalysisDomainHandler handler; |
| 28 |
| 29 Map<String, List<String>> analysisSubscriptions = {}; |
| 30 |
| 31 String projectPath = '/project'; |
| 32 String testFile = '/project/bin/test.dart'; |
| 33 String testCode; |
| 34 |
| 35 // Map<String, List<AnalysisError>> filesErrors = {}; |
| 36 // Map<String, List<Map<String, Object>>> filesHighlights = {}; |
| 37 // Map<String, List<Map<String, Object>>> filesNavigation = {}; |
| 38 |
| 39 |
| 40 AbstractAnalysisTest() { |
| 41 } |
| 42 |
| 43 void setUp() { |
| 44 serverChannel = new MockServerChannel(); |
| 45 resourceProvider = new MemoryResourceProvider(); |
| 46 server = new AnalysisServer(serverChannel, resourceProvider); |
| 47 handler = new AnalysisDomainHandler(server); |
| 48 // listen for notifications |
| 49 Stream<Notification> notificationStream = serverChannel.notificationControll
er.stream; |
| 50 notificationStream.listen((Notification notification) { |
| 51 processNotification(notification); |
| 52 }); |
| 53 // create an empty project |
| 54 _createEmptyProject(); |
| 55 } |
| 56 |
| 57 void addAnalysisSubscription(AnalysisService service, String file) { |
| 58 // add file to subscription |
| 59 var files = analysisSubscriptions[service.name]; |
| 60 if (files == null) { |
| 61 files = <String>[]; |
| 62 analysisSubscriptions[service.name] = files; |
| 63 } |
| 64 files.add(file); |
| 65 // set subscriptions |
| 66 Request request = new Request('0', METHOD_SET_ANALYSIS_SUBSCRIPTIONS); |
| 67 request.setParameter(SUBSCRIPTIONS, analysisSubscriptions); |
| 68 handleSuccessfulRequest(request); |
| 69 } |
| 70 |
| 71 void tearDown() { |
| 72 server.done(); |
| 73 handler = null; |
| 74 server = null; |
| 75 resourceProvider = null; |
| 76 serverChannel = null; |
| 77 } |
| 78 |
| 79 void processNotification(Notification notification) { |
| 80 // if (notification.event == NOTIFICATION_ERRORS) { |
| 81 // String file = notification.getParameter(FILE); |
| 82 // List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS); |
| 83 // filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList(); |
| 84 // } |
| 85 // if (notification.event == NOTIFICATION_HIGHLIGHTS) { |
| 86 // String file = notification.getParameter(FILE); |
| 87 // filesHighlights[file] = notification.getParameter(REGIONS); |
| 88 // } |
| 89 // if (notification.event == NOTIFICATION_NAVIGATION) { |
| 90 // String file = notification.getParameter(FILE); |
| 91 // filesNavigation[file] = notification.getParameter(REGIONS); |
| 92 // } |
| 93 } |
| 94 |
| 95 /** |
| 96 * Returns a [Future] that completes when the [AnalysisServer] finishes |
| 97 * all its scheduled tasks. |
| 98 */ |
| 99 Future waitForTasksFinished() { |
| 100 return waitForServerOperationsPerformed(server); |
| 101 } |
| 102 |
| 103 /** |
| 104 * Returns the offset of [search] in [testCode]. |
| 105 * Fails if not found. |
| 106 */ |
| 107 int findFileOffset(String path, String search) { |
| 108 File file = resourceProvider.getResource(path) as File; |
| 109 String code = file.createSource(UriKind.FILE_URI).contents.data; |
| 110 int offset = code.indexOf(search); |
| 111 expect(offset, isNot(-1), reason: '"$search" in\n$code'); |
| 112 return offset; |
| 113 } |
| 114 |
| 115 /** |
| 116 * Returns the offset of [search] in [testCode]. |
| 117 * Fails if not found. |
| 118 */ |
| 119 int findOffset(String search) { |
| 120 int offset = testCode.indexOf(search); |
| 121 expect(offset, isNot(-1)); |
| 122 return offset; |
| 123 } |
| 124 |
| 125 // /** |
| 126 // * Returns [AnalysisError]s recorded for the given [file]. |
| 127 // * May be empty, but not `null`. |
| 128 // */ |
| 129 // List<AnalysisError> getErrors(String file) { |
| 130 // List<AnalysisError> errors = filesErrors[file]; |
| 131 // if (errors != null) { |
| 132 // return errors; |
| 133 // } |
| 134 // return <AnalysisError>[]; |
| 135 // } |
| 136 // |
| 137 // /** |
| 138 // * Returns highlights recorded for the given [file]. |
| 139 // * May be empty, but not `null`. |
| 140 // */ |
| 141 // List<Map<String, Object>> getHighlights(String file) { |
| 142 // List<Map<String, Object>> highlights = filesHighlights[file]; |
| 143 // if (highlights != null) { |
| 144 // return highlights; |
| 145 // } |
| 146 // return []; |
| 147 // } |
| 148 // |
| 149 // /** |
| 150 // * Returns navigation regions recorded for the given [file]. |
| 151 // * May be empty, but not `null`. |
| 152 // */ |
| 153 // List<Map<String, Object>> getNavigation(String file) { |
| 154 // List<Map<String, Object>> navigation = filesNavigation[file]; |
| 155 // if (navigation != null) { |
| 156 // return navigation; |
| 157 // } |
| 158 // return []; |
| 159 // } |
| 160 // |
| 161 // /** |
| 162 // * Returns [AnalysisError]s recorded for the [testFile]. |
| 163 // * May be empty, but not `null`. |
| 164 // */ |
| 165 // List<AnalysisError> getTestErrors() { |
| 166 // return getErrors(testFile); |
| 167 // } |
| 168 // |
| 169 // /** |
| 170 // * Returns highlights recorded for the given [testFile]. |
| 171 // * May be empty, but not `null`. |
| 172 // */ |
| 173 // List<Map<String, Object>> getTestHighlights() { |
| 174 // return getHighlights(testFile); |
| 175 // } |
| 176 // |
| 177 // /** |
| 178 // * Returns navigation information recorded for the given [testFile]. |
| 179 // * May be empty, but not `null`. |
| 180 // */ |
| 181 // List<Map<String, Object>> getTestNavigation() { |
| 182 // return getNavigation(testFile); |
| 183 // } |
| 184 |
| 185 /** |
| 186 * Creates an empty project `/project/`. |
| 187 */ |
| 188 void _createEmptyProject() { |
| 189 resourceProvider.newFolder(projectPath); |
| 190 Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS); |
| 191 request.setParameter(INCLUDED, [projectPath]); |
| 192 request.setParameter(EXCLUDED, []); |
| 193 handleSuccessfulRequest(request); |
| 194 } |
| 195 |
| 196 // /** |
| 197 // * Creates a project with a single Dart file `/project/bin/test.dart` with |
| 198 // * the given [code]. |
| 199 // */ |
| 200 // void createSingleFileProject(code) { |
| 201 // this.testCode = _getCodeString(code); |
| 202 // resourceProvider.newFolder('/project'); |
| 203 // resourceProvider.newFile(testFile, testCode); |
| 204 // Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS); |
| 205 // request.setParameter(INCLUDED, ['/project']); |
| 206 // request.setParameter(EXCLUDED, []); |
| 207 // handleSuccessfulRequest(request); |
| 208 // } |
| 209 |
| 210 String addFile(String path, String content) { |
| 211 resourceProvider.newFile(path, content); |
| 212 return path; |
| 213 } |
| 214 |
| 215 String addTestFile(String content) { |
| 216 addFile(testFile, content); |
| 217 this.testCode = content; |
| 218 return testFile; |
| 219 } |
| 220 |
| 221 /** |
| 222 * Validates that the given [request] is handled successfully. |
| 223 */ |
| 224 void handleSuccessfulRequest(Request request) { |
| 225 Response response = handler.handleRequest(request); |
| 226 expect(response, isResponseSuccess('0')); |
| 227 } |
| 228 |
| 229 static String _getCodeString(code) { |
| 230 if (code is List<String>) { |
| 231 code = code.join('\n'); |
| 232 } |
| 233 return code as String; |
| 234 } |
| 235 } |
| 236 |
| 237 |
| 238 |
| 239 class AnalysisError { |
| 240 final String file; |
| 241 final String errorCode; |
| 242 final int offset; |
| 243 final int length; |
| 244 final String message; |
| 245 final String correction; |
| 246 AnalysisError(this.file, this.errorCode, this.offset, this.length, |
| 247 this.message, this.correction); |
| 248 |
| 249 @override |
| 250 String toString() { |
| 251 return 'NotificationError(file=$file; errorCode=$errorCode; ' |
| 252 'offset=$offset; length=$length; message=$message)'; |
| 253 } |
| 254 } |
| 255 |
| 256 |
| 257 AnalysisError _jsonToAnalysisError(Map<String, Object> json) { |
| 258 return new AnalysisError( |
| 259 json['file'], |
| 260 json['errorCode'], |
| 261 json['offset'], |
| 262 json['length'], |
| 263 json['message'], |
| 264 json['correction']); |
| 265 } |
| 266 |
| 267 |
| 268 int findIdentifierLength(String search) { |
| 269 int length = 0; |
| 270 while (length < search.length) { |
| 271 int c = search.codeUnitAt(length); |
| 272 if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) || |
| 273 c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) || |
| 274 c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) { |
| 275 break; |
| 276 } |
| 277 length++; |
| 278 } |
| 279 return length; |
| 280 } |
| OLD | NEW |