Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(738)

Side by Side Diff: pkg/analysis_server/test/integration/integration_tests.dart

Issue 396383002: More integration tests for analysis server. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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 library test.integration.analysis; 5 library test.integration.analysis;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:convert'; 9 import 'dart:convert';
10 import 'dart:io'; 10 import 'dart:io';
(...skipping 16 matching lines...) Expand all
27 Directory sourceDirectory; 27 Directory sourceDirectory;
28 28
29 /** 29 /**
30 * Map from file path to the list of analysis errors which have most recently 30 * Map from file path to the list of analysis errors which have most recently
31 * been received for the file. 31 * been received for the file.
32 */ 32 */
33 HashMap<String, dynamic> currentAnalysisErrors = new HashMap<String, dynamic>( 33 HashMap<String, dynamic> currentAnalysisErrors = new HashMap<String, dynamic>(
34 ); 34 );
35 35
36 /** 36 /**
37 * Create a source file with the given contents. [relativePath] 37 * Write a source file with the given contents. [relativePath]
38 * is relative to [sourceDirectory]; on Windows any forward slashes it 38 * is relative to [sourceDirectory]; on Windows any forward slashes it
39 * contains are converted to backslashes. 39 * contains are converted to backslashes.
40 *
41 * If the file didn't previously exist, it is created. If it did, it is
42 * overwritten.
40 */ 43 */
41 void createFile(String relativePath, String contents) { 44 void writeFile(String relativePath, String contents) {
42 String absolutePath = normalizePath(relativePath); 45 String absolutePath = normalizePath(relativePath);
43 new Directory(dirname(absolutePath)).createSync(recursive: true); 46 new Directory(dirname(absolutePath)).createSync(recursive: true);
44 new File(absolutePath).writeAsStringSync(contents); 47 new File(absolutePath).writeAsStringSync(contents);
45 } 48 }
46 49
47 /** 50 /**
48 * Convert the given [relativePath] to an absolute path, by interpreting it 51 * Convert the given [relativePath] to an absolute path, by interpreting it
49 * relative to [sourceDirectory]. On Windows any forward slashes in 52 * relative to [sourceDirectory]. On Windows any forward slashes in
50 * [relativePath] are converted to backslashes. 53 * [relativePath] are converted to backslashes.
51 */ 54 */
52 String normalizePath(String relativePath) { 55 String normalizePath(String relativePath) {
53 return join(sourceDirectory.path, relativePath.replaceAll('/', separator)); 56 return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
54 } 57 }
55 58
56 /** 59 /**
57 * Send the server an 'analysis.setAnalysisRoots' command. 60 * Send the server an 'analysis.setAnalysisRoots' command.
58 */ 61 */
59 Future setAnalysisRoots(List<String> relativeRoots) { 62 Future setAnalysisRoots(List<String> relativeRoots) {
60 return server.send('analysis.setAnalysisRoots', { 63 return server.send('analysis.setAnalysisRoots', {
61 'included': relativeRoots.map(normalizePath).toList(), 64 'included': relativeRoots.map(normalizePath).toList(),
62 'excluded': [] 65 'excluded': []
63 }); 66 });
64 } 67 }
65 68
66 /** 69 /**
70 * Send the server a 'server.setSubscriptions' command.
71 */
72 Future server_setSubscriptions(List<String> subscriptions) {
73 return server.send('server.setSubscriptions', {
74 'subscriptions': subscriptions
75 });
76 }
77
78 /**
67 * Return a future which will complete when a 'server.status' notification is 79 * Return a future which will complete when a 'server.status' notification is
68 * received from the server with 'analyzing' set to false. 80 * received from the server with 'analyzing' set to false.
69 * 81 *
70 * The future will only be completed by 'server.status' notifications that are 82 * The future will only be completed by 'server.status' notifications that are
71 * received after this function call. So it is safe to use this getter 83 * received after this function call. So it is safe to use this getter
72 * multiple times in one test; each time it is used it will wait afresh for 84 * multiple times in one test; each time it is used it will wait afresh for
73 * analysis to finish. 85 * analysis to finish.
74 */ 86 */
75 Future get analysisFinished { 87 Future get analysisFinished {
76 Completer completer = new Completer(); 88 Completer completer = new Completer();
77 StreamSubscription subscription; 89 StreamSubscription subscription;
78 subscription = server.onNotification('server.status').listen((params) { 90 subscription = server.onNotification('server.status').listen((params) {
79 if (!params['analysis']['analyzing']) { 91 bool analysisComplete = false;
92 try {
93 analysisComplete = !params['analysis']['analyzing'];
94 } catch (_) {
95 // Status message was mal-formed or missing optional parameters. That's
96 // fine, since we'll detect a mal-formed status message below.
97 }
98 if (analysisComplete) {
80 completer.complete(params); 99 completer.complete(params);
81 subscription.cancel(); 100 subscription.cancel();
82 } 101 }
102 expect(params, isServerStatusParams);
83 }); 103 });
84 return completer.future; 104 return completer.future;
85 } 105 }
86 106
87 /** 107 /**
88 * Print out any messages exchanged with the server. If some messages have 108 * Print out any messages exchanged with the server. If some messages have
89 * already been exchanged with the server, they are printed out immediately. 109 * already been exchanged with the server, they are printed out immediately.
90 */ 110 */
91 void debugStdio() { 111 void debugStdio() {
92 server.debugStdio(); 112 server.debugStdio();
(...skipping 24 matching lines...) Expand all
117 }); 137 });
118 } 138 }
119 } 139 }
120 140
121 // Matchers for data types defined in the analysis server API 141 // Matchers for data types defined in the analysis server API
122 // ========================================================== 142 // ==========================================================
123 // TODO(paulberry): add more matchers. 143 // TODO(paulberry): add more matchers.
124 144
125 const Matcher isString = const isInstanceOf<String>('String'); 145 const Matcher isString = const isInstanceOf<String>('String');
126 146
127 const Matcher isInt = const isInstanceOf<int>('Int'); 147 const Matcher isInt = const isInstanceOf<int>('int');
128 148
129 const Matcher isResultResponse = const MatchesJsonObject('result response', cons t { 149 const Matcher isBool = const isInstanceOf<bool>('bool');
150
151 const Matcher isResultResponse = const MatchesJsonObject('result response',
152 const {
130 'id': isString 153 'id': isString
131 }, optionalFields: const { 154 }, optionalFields: const {
132 'result': anything 155 'result': anything
133 }); 156 });
134 157
135 const Matcher isError = const MatchesJsonObject('Error', const { 158 const Matcher isError = const MatchesJsonObject('Error', const {
136 // TODO(paulberry): once we decide what the set of permitted error codes are, 159 // TODO(paulberry): once we decide what the set of permitted error codes are,
137 // add validation for 'code'. 160 // add validation for 'code'.
138 'code': anything, 161 'code': anything,
139 'message': isString, 162 'message': isString
163 }, optionalFields: const {
164 // TODO(paulberry): API spec says that 'data' is required, but sometimes we
165 // don't see it (example: error "Expected parameter subscriptions to be a
166 // string list map" in response to a malformed "analysis.setSubscriptions"
167 // command).
140 'data': anything 168 'data': anything
141 }); 169 });
142 170
143 const Matcher isErrorResponse = const MatchesJsonObject('error response', const { 171 const Matcher isErrorResponse = const MatchesJsonObject('error response', const
172 {
144 'id': isString, 173 'id': isString,
145 'error': isError 174 'error': isError
146 }); 175 });
147 176
148 const Matcher isNotification = const MatchesJsonObject('notification', const { 177 const Matcher isNotification = const MatchesJsonObject('notification', const {
149 'event': isString 178 'event': isString
150 }, optionalFields: const { 179 }, optionalFields: const {
151 'params': isMap 180 'params': isMap
152 }); 181 });
153 182
183 const Matcher isServerGetVersionResult = const MatchesJsonObject(
184 'server.getVersion result', const {
185 'version': isString
186 });
187
188 const Matcher isServerStatusParams = const MatchesJsonObject(
189 'server.status params', null, optionalFields: const {
190 'analysis': isAnalysisStatus
191 });
192
154 final Matcher isErrorSeverity = isIn(['INFO', 'WARNING', 'ERROR']); 193 final Matcher isErrorSeverity = isIn(['INFO', 'WARNING', 'ERROR']);
155 194
156 final Matcher isErrorType = isIn(['COMPILE_TIME_ERROR', 'HINT', 195 final Matcher isErrorType = isIn(['COMPILE_TIME_ERROR', 'HINT',
157 'STATIC_TYPE_WARNING', 'STATIC_WARNING', 'SYNTACTIC_ERROR', 'TODO']); 196 'STATIC_TYPE_WARNING', 'STATIC_WARNING', 'SYNTACTIC_ERROR', 'TODO']);
158 197
159 const Matcher isLocation = const MatchesJsonObject('Location', const { 198 const Matcher isLocation = const MatchesJsonObject('Location', const {
160 'file': isString, 199 'file': isString,
161 'offset': isInt, 200 'offset': isInt,
162 'length': isInt, 201 'length': isInt,
163 'startLine': isInt, 202 'startLine': isInt,
164 'startColumn': isInt 203 'startColumn': isInt
165 }); 204 });
166 205
167 final Matcher isAnalysisError = new MatchesJsonObject('AnalysisError', { 206 final Matcher isAnalysisError = new MatchesJsonObject('AnalysisError', {
168 'severity': isErrorSeverity, 207 'severity': isErrorSeverity,
169 'type': isErrorType, 208 'type': isErrorType,
170 'location': isLocation, 209 'location': isLocation,
171 'message': isString, 210 'message': isString,
172 }, optionalFields: { 211 }, optionalFields: {
173 'correction': isString, 212 'correction': isString,
174 // TODO(paulberry): remove 'errorCode' once server stops sending it 213 // TODO(paulberry): remove 'errorCode' once server stops sending it
175 'errorCode': anything 214 'errorCode': anything
176 }); 215 });
177 216
217 const Matcher isAnalysisStatus = const MatchesJsonObject('AnalysisStatus', const
218 {
219 'analyzing': isBool
220 }, optionalFields: const {
221 'analysisTarget': isString
222 });
223
178 224
179 /** 225 /**
180 * Type of closures used by MatchesJsonObject to record field mismatches. 226 * Type of closures used by MatchesJsonObject to record field mismatches.
181 */ 227 */
182 typedef Description MismatchDescriber(Description mismatchDescription, bool 228 typedef Description MismatchDescriber(Description mismatchDescription, bool
183 verbose); 229 verbose);
184 230
185 /** 231 /**
186 * Matcher that matches a JSON object, with a given set of required and 232 * Matcher that matches a JSON object, with a given set of required and
187 * optional fields, and their associated types (expressed as [Matcher]s). 233 * optional fields, and their associated types (expressed as [Matcher]s).
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 * [valueMatcher]. If it doesn't match, record a closure in [mismatches] 324 * [valueMatcher]. If it doesn't match, record a closure in [mismatches]
279 * which can describe the mismatch. 325 * which can describe the mismatch.
280 */ 326 */
281 void _checkField(String key, value, Matcher 327 void _checkField(String key, value, Matcher
282 valueMatcher, List<MismatchDescriber> mismatches) { 328 valueMatcher, List<MismatchDescriber> mismatches) {
283 Map subState = {}; 329 Map subState = {};
284 if (!valueMatcher.matches(value, subState)) { 330 if (!valueMatcher.matches(value, subState)) {
285 mismatches.add((Description mismatchDescription, bool verbose) { 331 mismatches.add((Description mismatchDescription, bool verbose) {
286 mismatchDescription = mismatchDescription.add( 332 mismatchDescription = mismatchDescription.add(
287 'contains malformed field ').addDescriptionOf(key).add(' (should be ' 333 'contains malformed field ').addDescriptionOf(key).add(' (should be '
288 ).addDescriptionOf(valueMatcher).add('; '); 334 ).addDescriptionOf(valueMatcher);
289 mismatchDescription = valueMatcher.describeMismatch(value, 335 String subDescription = valueMatcher.describeMismatch(value,
290 mismatchDescription, subState, verbose); 336 new StringDescription(), subState, false).toString();
337 if (subDescription.isNotEmpty) {
338 mismatchDescription = mismatchDescription.add('; ').add(subDescription
339 );
340 }
291 return mismatchDescription.add(')'); 341 return mismatchDescription.add(')');
292 }); 342 });
293 } 343 }
294 } 344 }
295 } 345 }
296 346
297 /** 347 /**
298 * Instances of the class [Server] manage a connection to a server process, and 348 * Instances of the class [Server] manage a connection to a server process, and
299 * facilitate communication to and from the server. 349 * facilitate communication to and from the server.
300 */ 350 */
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 expect(messageAsMap['id'], isString); 437 expect(messageAsMap['id'], isString);
388 String id = message['id']; 438 String id = message['id'];
389 Completer completer = server._pendingCommands[id]; 439 Completer completer = server._pendingCommands[id];
390 if (completer == null) { 440 if (completer == null) {
391 fail('Unexpected response from server: id=$id'); 441 fail('Unexpected response from server: id=$id');
392 } else { 442 } else {
393 server._pendingCommands.remove(id); 443 server._pendingCommands.remove(id);
394 } 444 }
395 if (messageAsMap.containsKey('error')) { 445 if (messageAsMap.containsKey('error')) {
396 // TODO(paulberry): propagate the error info to the completer. 446 // TODO(paulberry): propagate the error info to the completer.
397 completer.completeError(null); 447 completer.completeError(new UnimplementedError(
448 'Server responded with an error'));
398 // Check that the message is well-formed. We do this after calling 449 // Check that the message is well-formed. We do this after calling
399 // completer.completeError() so that we don't stall the test in the 450 // completer.completeError() so that we don't stall the test in the
400 // event of an error. 451 // event of an error.
401 expect(message, isErrorResponse); 452 expect(message, isErrorResponse);
402 } else { 453 } else {
403 completer.complete(messageAsMap['result']); 454 completer.complete(messageAsMap['result']);
404 // Check that the message is well-formed. We do this after calling 455 // Check that the message is well-formed. We do this after calling
405 // completer.complete() so that we don't stall the test in the 456 // completer.complete() so that we don't stall the test in the
406 // event of an error. 457 // event of an error.
407 expect(message, isResultResponse); 458 expect(message, isResultResponse);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 * Record a message that was exchanged with the server, and print it out if 532 * Record a message that was exchanged with the server, and print it out if
482 * [debugStdio] has been called. 533 * [debugStdio] has been called.
483 */ 534 */
484 void _recordStdio(String line) { 535 void _recordStdio(String line) {
485 if (_debuggingStdio) { 536 if (_debuggingStdio) {
486 print(line); 537 print(line);
487 } 538 }
488 _recordedStdio.add(line); 539 _recordedStdio.add(line);
489 } 540 }
490 } 541 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698