OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Support for interacting with an analysis server running in a separate | 6 * Support for interacting with an analysis server running in a separate |
7 * process. | 7 * process. |
8 */ | 8 */ |
9 library analysis_server.test.stress.utilities.server; | 9 library analysis_server.test.stress.utilities.server; |
10 | 10 |
11 import 'dart:async'; | 11 import 'dart:async'; |
12 import 'dart:collection'; | 12 import 'dart:collection'; |
13 | 13 |
14 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 14 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
15 | 15 |
16 import '../../integration/integration_test_methods.dart'; | 16 import '../../integration/integration_test_methods.dart'; |
17 import '../../integration/integration_tests.dart' as base; | 17 import '../../integration/integration_tests.dart' as base; |
18 | 18 |
19 /** | 19 /** |
| 20 * ??? |
| 21 */ |
| 22 class ErrorMap { |
| 23 /** |
| 24 * A table mapping file paths to the errors associated with that file. |
| 25 */ |
| 26 final Map<String, List<AnalysisError>> pathMap = |
| 27 new HashMap<String, List<AnalysisError>>(); |
| 28 |
| 29 /** |
| 30 * Initialize a newly created error map. |
| 31 */ |
| 32 ErrorMap(); |
| 33 |
| 34 /** |
| 35 * Initialize a newly created error map to contain the same mapping as the |
| 36 * given [errorMap]. |
| 37 */ |
| 38 ErrorMap.from(ErrorMap errorMap) { |
| 39 pathMap.addAll(errorMap.pathMap); |
| 40 } |
| 41 |
| 42 void operator []=(String filePath, List<AnalysisError> errors) { |
| 43 pathMap[filePath] = errors; |
| 44 } |
| 45 |
| 46 /** |
| 47 * Compare the this error map with the state captured in the given [errorMap]. |
| 48 * Throw an exception if the two maps do not agree. |
| 49 */ |
| 50 String expectErrorMap(ErrorMap errorMap) { |
| 51 StringBuffer buffer = new StringBuffer(); |
| 52 _ErrorComparator comparator = new _ErrorComparator(buffer); |
| 53 comparator.compare(pathMap, errorMap.pathMap); |
| 54 if (buffer.length > 0) { |
| 55 return buffer.toString(); |
| 56 } |
| 57 return null; |
| 58 } |
| 59 } |
| 60 |
| 61 /** |
20 * An interface for starting and communicating with an analysis server running | 62 * An interface for starting and communicating with an analysis server running |
21 * in a separate process. | 63 * in a separate process. |
22 */ | 64 */ |
23 class Server extends base.Server with IntegrationTestMixin { | 65 class Server extends base.Server with IntegrationTestMixin { |
24 /** | 66 /** |
25 * A list containing the paths of files for which an overlay has been created. | 67 * A list containing the paths of files for which an overlay has been created. |
26 */ | 68 */ |
27 List<String> filesWithOverlays = <String>[]; | 69 List<String> filesWithOverlays = <String>[]; |
28 | 70 |
29 /** | 71 /** |
30 * A table mapping the absolute paths of files to the most recent set of | 72 * A mapping from the absolute paths of files to the most recent set of errors |
31 * errors received for that file. | 73 * received for that file. |
32 */ | 74 */ |
33 Map<String, List<AnalysisError>> _errorMap = | 75 ErrorMap _errorMap = new ErrorMap(); |
34 new HashMap<String, List<AnalysisError>>(); | |
35 | 76 |
36 /** | 77 /** |
37 * Initialize a new analysis server. The analysis server is not running and | 78 * Initialize a new analysis server. The analysis server is not running and |
38 * must be started using [start]. | 79 * must be started using [start]. |
39 */ | 80 */ |
40 Server() { | 81 Server() { |
41 initializeInttestMixin(); | 82 initializeInttestMixin(); |
42 onAnalysisErrors.listen(_recordErrors); | 83 onAnalysisErrors.listen(_recordErrors); |
43 } | 84 } |
44 | 85 |
45 /** | 86 /** |
| 87 * Return a list of the paths of files that are currently being analyzed. |
| 88 */ |
| 89 List<String> get analyzedDartFiles { |
| 90 // TODO(brianwilkerson) Implement this. |
| 91 return <String>[]; |
| 92 } |
| 93 |
| 94 /** |
46 * Return a table mapping the absolute paths of files to the most recent set | 95 * Return a table mapping the absolute paths of files to the most recent set |
47 * of errors received for that file. The content of the map will not change | 96 * of errors received for that file. The content of the map will not change |
48 * when new sets of errors are received. | 97 * when new sets of errors are received. |
49 */ | 98 */ |
50 Map<String, List<AnalysisError>> get errorMap => | 99 ErrorMap get errorMap => new ErrorMap.from(_errorMap); |
51 new HashMap<String, List<AnalysisError>>.from(_errorMap); | |
52 | 100 |
53 @override | 101 @override |
54 base.Server get server => this; | 102 base.Server get server => this; |
55 | 103 |
56 /** | 104 /** |
| 105 * Compute a mapping from each of the file paths in the given list of |
| 106 * [filePaths] to the list of errors in the file at that path. |
| 107 */ |
| 108 Future<ErrorMap> computeErrorMap(List<String> filePaths) async { |
| 109 ErrorMap errorMap = new ErrorMap(); |
| 110 List<Future> futures = <Future>[]; |
| 111 for (String filePath in filePaths) { |
| 112 futures.add(sendAnalysisGetErrors(filePath) |
| 113 .then((AnalysisGetErrorsResult result) { |
| 114 errorMap[filePath] = result.errors; |
| 115 })); |
| 116 } |
| 117 await Future.wait(futures); |
| 118 return errorMap; |
| 119 } |
| 120 |
| 121 /** |
57 * Remove any existing overlays. | 122 * Remove any existing overlays. |
58 */ | 123 */ |
59 Future<AnalysisUpdateContentResult> removeAllOverlays() { | 124 Future<AnalysisUpdateContentResult> removeAllOverlays() { |
60 Map<String, dynamic> files = new HashMap<String, dynamic>(); | 125 Map<String, dynamic> files = new HashMap<String, dynamic>(); |
61 for (String path in filesWithOverlays) { | 126 for (String path in filesWithOverlays) { |
62 files[path] = new RemoveContentOverlay(); | 127 files[path] = new RemoveContentOverlay(); |
63 } | 128 } |
64 return sendAnalysisUpdateContent(files); | 129 return sendAnalysisUpdateContent(files); |
65 } | 130 } |
66 | 131 |
(...skipping 10 matching lines...) Expand all Loading... |
77 return super.sendAnalysisUpdateContent(files); | 142 return super.sendAnalysisUpdateContent(files); |
78 } | 143 } |
79 | 144 |
80 /** | 145 /** |
81 * Record the errors in the given [params]. | 146 * Record the errors in the given [params]. |
82 */ | 147 */ |
83 void _recordErrors(AnalysisErrorsParams params) { | 148 void _recordErrors(AnalysisErrorsParams params) { |
84 _errorMap[params.file] = params.errors; | 149 _errorMap[params.file] = params.errors; |
85 } | 150 } |
86 } | 151 } |
| 152 |
| 153 /** |
| 154 * A utility class used to compare two sets of errors. |
| 155 */ |
| 156 class _ErrorComparator { |
| 157 /** |
| 158 * An empty list of analysis errors. |
| 159 */ |
| 160 static final List<AnalysisError> NO_ERRORS = <AnalysisError>[]; |
| 161 |
| 162 /** |
| 163 * The buffer to which an error description will be written if any of the |
| 164 * files have different errors than are expected. |
| 165 */ |
| 166 final StringBuffer buffer; |
| 167 |
| 168 /** |
| 169 * Initialize a newly created comparator to write to the given [buffer]. |
| 170 */ |
| 171 _ErrorComparator(this.buffer); |
| 172 |
| 173 /** |
| 174 * Compare the [actualErrorMap] and the [expectedErrorMap], writing a |
| 175 * description to the [buffer] if they are not the same. The error maps are |
| 176 * expected to be maps from absolute file paths to the list of actual or |
| 177 * expected errors. |
| 178 */ |
| 179 void compare(Map<String, List<AnalysisError>> actualErrorMap, |
| 180 Map<String, List<AnalysisError>> expectedErrorMap) { |
| 181 Set<String> allFiles = new HashSet(); |
| 182 allFiles.addAll(actualErrorMap.keys); |
| 183 allFiles.addAll(expectedErrorMap.keys); |
| 184 List<String> sortedFiles = allFiles.toList()..sort(); |
| 185 for (String filePath in sortedFiles) { |
| 186 List<AnalysisError> actualErrors = actualErrorMap[filePath]; |
| 187 List<AnalysisError> expectedErrors = expectedErrorMap[filePath]; |
| 188 _compareLists( |
| 189 filePath, actualErrors ?? NO_ERRORS, expectedErrors ?? NO_ERRORS); |
| 190 } |
| 191 } |
| 192 |
| 193 /** |
| 194 * Compare the [actualErrors] and [expectedErrors], writing a description to |
| 195 * the [buffer] if they are not the same. |
| 196 */ |
| 197 void _compareLists(String filePath, List<AnalysisError> actualErrors, |
| 198 List<AnalysisError> expectedErrors) { |
| 199 List<AnalysisError> remainingExpected = |
| 200 new List<AnalysisError>.from(expectedErrors); |
| 201 for (AnalysisError actualError in actualErrors) { |
| 202 AnalysisError expectedError = _findError(remainingExpected, actualError); |
| 203 if (expectedError == null) { |
| 204 _writeReport(filePath, actualErrors, expectedErrors); |
| 205 return; |
| 206 } |
| 207 remainingExpected.remove(expectedError); |
| 208 } |
| 209 if (remainingExpected.isNotEmpty) { |
| 210 _writeReport(filePath, actualErrors, expectedErrors); |
| 211 } |
| 212 } |
| 213 |
| 214 /** |
| 215 * Return `true` if the [firstError] and the [secondError] are equivalent. |
| 216 */ |
| 217 bool _equalErrors(AnalysisError firstError, AnalysisError secondError) => |
| 218 firstError.severity == secondError.severity && |
| 219 firstError.type == secondError.type && |
| 220 _equalLocations(firstError.location, secondError.location) && |
| 221 firstError.message == secondError.message; |
| 222 |
| 223 /** |
| 224 * Return `true` if the [firstLocation] and the [secondLocation] are |
| 225 * equivalent. |
| 226 */ |
| 227 bool _equalLocations(Location firstLocation, Location secondLocation) => |
| 228 firstLocation.file == secondLocation.file && |
| 229 firstLocation.offset == secondLocation.offset && |
| 230 firstLocation.length == secondLocation.length; |
| 231 |
| 232 /** |
| 233 * Search through the given list of [errors] for an error that is equal to the |
| 234 * [targetError]. If one is found, return it, otherwise return `null`. |
| 235 */ |
| 236 AnalysisError _findError( |
| 237 List<AnalysisError> errors, AnalysisError targetError) { |
| 238 for (AnalysisError error in errors) { |
| 239 if (_equalErrors(error, targetError)) { |
| 240 return error; |
| 241 } |
| 242 } |
| 243 return null; |
| 244 } |
| 245 |
| 246 /** |
| 247 * Write the given list of [errors], preceded by a header beginning with the |
| 248 * given [prefix]. |
| 249 */ |
| 250 void _writeErrors(String prefix, List<AnalysisError> errors) { |
| 251 buffer.write(prefix); |
| 252 buffer.write(errors.length); |
| 253 buffer.write(' errors:'); |
| 254 for (AnalysisError error in errors) { |
| 255 buffer.writeln(); |
| 256 Location location = error.location; |
| 257 int offset = location.offset; |
| 258 buffer.write(' '); |
| 259 buffer.write(location.file); |
| 260 buffer.write(' ('); |
| 261 buffer.write(offset); |
| 262 buffer.write('..'); |
| 263 buffer.write(offset + location.length); |
| 264 buffer.write(') '); |
| 265 buffer.write(error.severity); |
| 266 buffer.write(', '); |
| 267 buffer.write(error.type); |
| 268 buffer.write(' : '); |
| 269 buffer.write(error.message); |
| 270 } |
| 271 } |
| 272 |
| 273 /** |
| 274 * Write a report of the differences between the [actualErrors] and the |
| 275 * [expectedErrors]. The errors are reported as being from the file at the |
| 276 * given [filePath]. |
| 277 */ |
| 278 void _writeReport(String filePath, List<AnalysisError> actualErrors, |
| 279 List<AnalysisError> expectedErrors) { |
| 280 if (buffer.length > 0) { |
| 281 buffer.writeln(); |
| 282 buffer.writeln(); |
| 283 } |
| 284 buffer.writeln(filePath); |
| 285 _writeErrors(' Expected ', expectedErrors); |
| 286 buffer.writeln(); |
| 287 _writeErrors(' Found ', expectedErrors); |
| 288 } |
| 289 } |
OLD | NEW |