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

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

Issue 631553002: Change integration test notifications to use structured objects. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 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 24 matching lines...) Expand all
35 35
36 /** 36 /**
37 * Temporary directory in which source files can be stored. 37 * Temporary directory in which source files can be stored.
38 */ 38 */
39 Directory sourceDirectory; 39 Directory sourceDirectory;
40 40
41 /** 41 /**
42 * Map from file path to the list of analysis errors which have most recently 42 * Map from file path to the list of analysis errors which have most recently
43 * been received for the file. 43 * been received for the file.
44 */ 44 */
45 HashMap<String, dynamic> currentAnalysisErrors = new HashMap<String, dynamic>( 45 HashMap<String, List<AnalysisError>> currentAnalysisErrors =
46 ); 46 new HashMap<String, List<AnalysisError>>();
47 47
48 /** 48 /**
49 * True if the teardown process should skip sending a "server.shutdown" 49 * True if the teardown process should skip sending a "server.shutdown"
50 * request (e.g. because the server is known to have already shutdown). 50 * request (e.g. because the server is known to have already shutdown).
51 */ 51 */
52 bool skipShutdown = false; 52 bool skipShutdown = false;
53 53
54 /** 54 /**
55 * Data associated with the "server.connected" notification that was received 55 * Data associated with the "server.connected" notification that was received
56 * when the server started up. 56 * when the server started up.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 * received after this function call. So it is safe to use this getter 111 * received after this function call. So it is safe to use this getter
112 * multiple times in one test; each time it is used it will wait afresh for 112 * multiple times in one test; each time it is used it will wait afresh for
113 * analysis to finish. 113 * analysis to finish.
114 */ 114 */
115 Future get analysisFinished { 115 Future get analysisFinished {
116 Completer completer = new Completer(); 116 Completer completer = new Completer();
117 StreamSubscription subscription; 117 StreamSubscription subscription;
118 // This will only work if the caller has already subscribed to 118 // This will only work if the caller has already subscribed to
119 // SERVER_STATUS (e.g. using sendServerSetSubscriptions(['STATUS'])) 119 // SERVER_STATUS (e.g. using sendServerSetSubscriptions(['STATUS']))
120 expect(_subscribedToServerStatus, isTrue); 120 expect(_subscribedToServerStatus, isTrue);
121 subscription = onServerStatus.listen((params) { 121 subscription = onServerStatus.listen((ServerStatusParams params) {
122 bool analysisComplete = false; 122 if (!params.analysis.isAnalyzing) {
123 try {
124 analysisComplete = !params['analysis']['isAnalyzing'];
125 } catch (_) {
126 // Status message was mal-formed or missing optional parameters. That's
127 // fine, since we'll detect a mal-formed status message below.
128 }
129 if (analysisComplete) {
130 completer.complete(params); 123 completer.complete(params);
131 subscription.cancel(); 124 subscription.cancel();
132 } 125 }
133 expect(params, isServerStatusParams);
134 }); 126 });
135 return completer.future; 127 return completer.future;
136 } 128 }
137 129
138 /** 130 /**
139 * Print out any messages exchanged with the server. If some messages have 131 * Print out any messages exchanged with the server. If some messages have
140 * already been exchanged with the server, they are printed out immediately. 132 * already been exchanged with the server, they are printed out immediately.
141 */ 133 */
142 void debugStdio() { 134 void debugStdio() {
143 server.debugStdio(); 135 server.debugStdio();
144 } 136 }
145 137
146 @override 138 @override
147 Future sendServerSetSubscriptions(List<ServerService> subscriptions) { 139 Future sendServerSetSubscriptions(List<ServerService> subscriptions) {
148 _subscribedToServerStatus = subscriptions.contains(ServerService.STATUS); 140 _subscribedToServerStatus = subscriptions.contains(ServerService.STATUS);
149 return super.sendServerSetSubscriptions(subscriptions); 141 return super.sendServerSetSubscriptions(subscriptions);
150 } 142 }
151 143
152 /** 144 /**
153 * The server is automatically started before every test, and a temporary 145 * The server is automatically started before every test, and a temporary
154 * [sourceDirectory] is created. 146 * [sourceDirectory] is created.
155 */ 147 */
156 Future setUp() { 148 Future setUp() {
157 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer'); 149 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer');
158 150
159 onAnalysisErrors.listen((params) { 151 onAnalysisErrors.listen((AnalysisErrorsParams params) {
160 currentAnalysisErrors[params['file']] = params['errors']; 152 currentAnalysisErrors[params.file] = params.errors;
161 }); 153 });
162 Completer serverConnected = new Completer(); 154 Completer serverConnected = new Completer();
163 onServerConnected.listen((_) { 155 onServerConnected.listen((_) {
164 expect(serverConnected.isCompleted, isFalse); 156 expect(serverConnected.isCompleted, isFalse);
165 serverConnected.complete(); 157 serverConnected.complete();
166 }); 158 });
167 return server.start(dispatchNotification).then((params) { 159 return server.start(dispatchNotification).then((params) {
168 serverConnectedParams = params; 160 serverConnectedParams = params;
169 server.exitCode.then((_) { 161 server.exitCode.then((_) {
170 skipShutdown = true; 162 skipShutdown = true;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 return true; 232 return true;
241 } else { 233 } else {
242 addStateInfo(matchState, { 234 addStateInfo(matchState, {
243 'mismatches': mismatches 235 'mismatches': mismatches
244 }); 236 });
245 return false; 237 return false;
246 } 238 }
247 } 239 }
248 240
249 @override 241 @override
250 Description describeMismatch(item, Description mismatchDescription, Map 242 Description describeMismatch(item, Description mismatchDescription,
251 matchState, bool verbose) { 243 Map matchState, bool verbose) {
252 List<MismatchDescriber> mismatches = matchState['mismatches']; 244 List<MismatchDescriber> mismatches = matchState['mismatches'];
253 if (mismatches != null) { 245 if (mismatches != null) {
254 for (int i = 0; i < mismatches.length; i++) { 246 for (int i = 0; i < mismatches.length; i++) {
255 MismatchDescriber mismatch = mismatches[i]; 247 MismatchDescriber mismatch = mismatches[i];
256 if (i > 0) { 248 if (i > 0) {
257 if (mismatches.length == 2) { 249 if (mismatches.length == 2) {
258 mismatchDescription = mismatchDescription.add(' and '); 250 mismatchDescription = mismatchDescription.add(' and ');
259 } else if (i == mismatches.length - 1) { 251 } else if (i == mismatches.length - 1) {
260 mismatchDescription = mismatchDescription.add(', and '); 252 mismatchDescription = mismatchDescription.add(', and ');
261 } else { 253 } else {
262 mismatchDescription = mismatchDescription.add(', '); 254 mismatchDescription = mismatchDescription.add(', ');
263 } 255 }
264 } 256 }
265 mismatchDescription = mismatch(mismatchDescription); 257 mismatchDescription = mismatch(mismatchDescription);
266 } 258 }
267 return mismatchDescription; 259 return mismatchDescription;
268 } else { 260 } else {
269 return super.describeMismatch(item, mismatchDescription, matchState, 261 return super.describeMismatch(
262 item,
263 mismatchDescription,
264 matchState,
270 verbose); 265 verbose);
271 } 266 }
272 } 267 }
273 268
274 /** 269 /**
275 * Populate [mismatches] with descriptions of all the ways in which [item] 270 * Populate [mismatches] with descriptions of all the ways in which [item]
276 * does not match. 271 * does not match.
277 */ 272 */
278 void populateMismatches(item, List<MismatchDescriber> mismatches); 273 void populateMismatches(item, List<MismatchDescriber> mismatches);
279 274
280 /** 275 /**
281 * Create a [MismatchDescriber] describing a mismatch with a simple string. 276 * Create a [MismatchDescriber] describing a mismatch with a simple string.
282 */ 277 */
283 MismatchDescriber simpleDescription(String description) => (Description 278 MismatchDescriber simpleDescription(String description) =>
284 mismatchDescription) { 279 (Description mismatchDescription) {
285 mismatchDescription.add(description); 280 mismatchDescription.add(description);
286 }; 281 };
287 282
288 /** 283 /**
289 * Check the type of a substructure whose value is [item], using [matcher]. 284 * Check the type of a substructure whose value is [item], using [matcher].
290 * If it doesn't match, record a closure in [mismatches] which can describe 285 * If it doesn't match, record a closure in [mismatches] which can describe
291 * the mismatch. [describeSubstructure] is used to describe which 286 * the mismatch. [describeSubstructure] is used to describe which
292 * substructure did not match. 287 * substructure did not match.
293 */ 288 */
294 checkSubstructure(item, Matcher matcher, List<MismatchDescriber> 289 checkSubstructure(item, Matcher matcher, List<MismatchDescriber> mismatches,
295 mismatches, Description describeSubstructure(Description)) { 290 Description describeSubstructure(Description)) {
296 Map subState = {}; 291 Map subState = {};
297 if (!matcher.matches(item, subState)) { 292 if (!matcher.matches(item, subState)) {
298 mismatches.add((Description mismatchDescription) { 293 mismatches.add((Description mismatchDescription) {
299 mismatchDescription = mismatchDescription.add('contains malformed '); 294 mismatchDescription = mismatchDescription.add('contains malformed ');
300 mismatchDescription = describeSubstructure(mismatchDescription); 295 mismatchDescription = describeSubstructure(mismatchDescription);
301 mismatchDescription = mismatchDescription.add(' (should be ' 296 mismatchDescription =
302 ).addDescriptionOf(matcher); 297 mismatchDescription.add(' (should be ').addDescriptionOf(matcher);
303 String subDescription = matcher.describeMismatch(item, 298 String subDescription = matcher.describeMismatch(
304 new StringDescription(), subState, false).toString(); 299 item,
300 new StringDescription(),
301 subState,
302 false).toString();
305 if (subDescription.isNotEmpty) { 303 if (subDescription.isNotEmpty) {
306 mismatchDescription = mismatchDescription.add('; ').add(subDescription 304 mismatchDescription =
307 ); 305 mismatchDescription.add('; ').add(subDescription);
308 } 306 }
309 return mismatchDescription.add(')'); 307 return mismatchDescription.add(')');
310 }); 308 });
311 } 309 }
312 } 310 }
313 } 311 }
314 312
315 /** 313 /**
316 * Matcher that matches a String drawn from a limited set. 314 * Matcher that matches a String drawn from a limited set.
317 */ 315 */
318 class MatchesEnum extends Matcher { 316 class MatchesEnum extends Matcher {
319 /** 317 /**
320 * Short description of the expected type. 318 * Short description of the expected type.
321 */ 319 */
322 final String description; 320 final String description;
323 321
324 /** 322 /**
325 * The set of enum values that are allowed. 323 * The set of enum values that are allowed.
326 */ 324 */
327 final List<String> allowedValues; 325 final List<String> allowedValues;
328 326
329 const MatchesEnum(this.description, this.allowedValues); 327 const MatchesEnum(this.description, this.allowedValues);
330 328
331 @override 329 @override
332 bool matches(item, Map matchState) { 330 bool matches(item, Map matchState) {
333 return allowedValues.contains(item); 331 return allowedValues.contains(item);
334 } 332 }
335 333
336 @override 334 @override
337 Description describe(Description description) => description.add( 335 Description describe(Description description) =>
338 this.description); 336 description.add(this.description);
339 } 337 }
340 338
341 /** 339 /**
342 * Matcher that matches a JSON object, with a given set of required and 340 * Matcher that matches a JSON object, with a given set of required and
343 * optional fields, and their associated types (expressed as [Matcher]s). 341 * optional fields, and their associated types (expressed as [Matcher]s).
344 */ 342 */
345 class MatchesJsonObject extends _RecursiveMatcher { 343 class MatchesJsonObject extends _RecursiveMatcher {
346 /** 344 /**
347 * Short description of the expected type. 345 * Short description of the expected type.
348 */ 346 */
349 final String description; 347 final String description;
350 348
351 /** 349 /**
352 * Fields that are required to be in the JSON object, and [Matcher]s describin g 350 * Fields that are required to be in the JSON object, and [Matcher]s describin g
353 * their expected types. 351 * their expected types.
354 */ 352 */
355 final Map<String, Matcher> requiredFields; 353 final Map<String, Matcher> requiredFields;
356 354
357 /** 355 /**
358 * Fields that are optional in the JSON object, and [Matcher]s describing 356 * Fields that are optional in the JSON object, and [Matcher]s describing
359 * their expected types. 357 * their expected types.
360 */ 358 */
361 final Map<String, Matcher> optionalFields; 359 final Map<String, Matcher> optionalFields;
362 360
363 const 361 const MatchesJsonObject(this.description, this.requiredFields,
364 MatchesJsonObject(this.description, this.requiredFields, {this.optionalFie lds}); 362 {this.optionalFields});
365 363
366 @override 364 @override
367 void populateMismatches(item, List<MismatchDescriber> mismatches) { 365 void populateMismatches(item, List<MismatchDescriber> mismatches) {
368 if (item is! Map) { 366 if (item is! Map) {
369 mismatches.add(simpleDescription('is not a map')); 367 mismatches.add(simpleDescription('is not a map'));
370 return; 368 return;
371 } 369 }
372 if (requiredFields != null) { 370 if (requiredFields != null) {
373 requiredFields.forEach((String key, Matcher valueMatcher) { 371 requiredFields.forEach((String key, Matcher valueMatcher) {
374 if (!item.containsKey(key)) { 372 if (!item.containsKey(key)) {
375 mismatches.add((Description mismatchDescription) => 373 mismatches.add(
376 mismatchDescription.add('is missing field ').addDescriptionOf(key) .add(' (' 374 (Description mismatchDescription) =>
377 ).addDescriptionOf(valueMatcher).add(')')); 375 mismatchDescription.add(
376 'is missing field ').addDescriptionOf(
377 key).add(' (').addDescriptionOf(valueMatcher).add(')') );
378 } else { 378 } else {
379 _checkField(key, item[key], valueMatcher, mismatches); 379 _checkField(key, item[key], valueMatcher, mismatches);
380 } 380 }
381 }); 381 });
382 } 382 }
383 item.forEach((key, value) { 383 item.forEach((key, value) {
384 if (requiredFields != null && requiredFields.containsKey(key)) { 384 if (requiredFields != null && requiredFields.containsKey(key)) {
385 // Already checked this field 385 // Already checked this field
386 } else if (optionalFields != null && optionalFields.containsKey(key)) { 386 } else if (optionalFields != null && optionalFields.containsKey(key)) {
387 _checkField(key, value, optionalFields[key], mismatches); 387 _checkField(key, value, optionalFields[key], mismatches);
388 } else { 388 } else {
389 mismatches.add((Description mismatchDescription) => 389 mismatches.add(
390 mismatchDescription.add('has unexpected field ').addDescriptionOf(ke y)); 390 (Description mismatchDescription) =>
391 mismatchDescription.add('has unexpected field ').addDescriptionO f(key));
391 } 392 }
392 }); 393 });
393 } 394 }
394 395
395 @override 396 @override
396 Description describe(Description description) => description.add( 397 Description describe(Description description) =>
397 this.description); 398 description.add(this.description);
398 399
399 /** 400 /**
400 * Check the type of a field called [key], having value [value], using 401 * Check the type of a field called [key], having value [value], using
401 * [valueMatcher]. If it doesn't match, record a closure in [mismatches] 402 * [valueMatcher]. If it doesn't match, record a closure in [mismatches]
402 * which can describe the mismatch. 403 * which can describe the mismatch.
403 */ 404 */
404 void _checkField(String key, value, Matcher 405 void _checkField(String key, value, Matcher valueMatcher,
405 valueMatcher, List<MismatchDescriber> mismatches) { 406 List<MismatchDescriber> mismatches) {
406 checkSubstructure(value, valueMatcher, mismatches, (Description description) 407 checkSubstructure(
407 => description.add('field ').addDescriptionOf(key)); 408 value,
409 valueMatcher,
410 mismatches,
411 (Description description) => description.add('field ').addDescriptionOf( key));
408 } 412 }
409 } 413 }
410 414
411 /** 415 /**
412 * Matcher that matches a list of objects, each of which satisfies the given 416 * Matcher that matches a list of objects, each of which satisfies the given
413 * matcher. 417 * matcher.
414 */ 418 */
415 class _ListOf extends Matcher { 419 class _ListOf extends Matcher {
416 /** 420 /**
417 * Matcher which every element of the list must satisfy. 421 * Matcher which every element of the list must satisfy.
(...skipping 11 matching lines...) Expand all
429 433
430 @override 434 @override
431 bool matches(item, Map matchState) { 435 bool matches(item, Map matchState) {
432 if (item is! List) { 436 if (item is! List) {
433 return false; 437 return false;
434 } 438 }
435 return iterableMatcher.matches(item, matchState); 439 return iterableMatcher.matches(item, matchState);
436 } 440 }
437 441
438 @override 442 @override
439 Description describe(Description description) => description.add('List of ' 443 Description describe(Description description) =>
440 ).addDescriptionOf(elementMatcher); 444 description.add('List of ').addDescriptionOf(elementMatcher);
441 445
442 @override 446 @override
443 Description describeMismatch(item, Description mismatchDescription, Map 447 Description describeMismatch(item, Description mismatchDescription,
444 matchState, bool verbose) { 448 Map matchState, bool verbose) {
445 if (item is! List) { 449 if (item is! List) {
446 return super.describeMismatch(item, mismatchDescription, matchState, 450 return super.describeMismatch(
451 item,
452 mismatchDescription,
453 matchState,
447 verbose); 454 verbose);
448 } else { 455 } else {
449 return iterableMatcher.describeMismatch(item, mismatchDescription, 456 return iterableMatcher.describeMismatch(
450 matchState, verbose); 457 item,
458 mismatchDescription,
459 matchState,
460 verbose);
451 } 461 }
452 } 462 }
453 } 463 }
454 464
455 Matcher isListOf(Matcher elementMatcher) => new _ListOf(elementMatcher); 465 Matcher isListOf(Matcher elementMatcher) => new _ListOf(elementMatcher);
456 466
457 /** 467 /**
458 * Type of closures used by LazyMatcher. 468 * Type of closures used by LazyMatcher.
459 */ 469 */
460 typedef Matcher MatcherCreator(); 470 typedef Matcher MatcherCreator();
(...skipping 18 matching lines...) Expand all
479 489
480 LazyMatcher(this._creator); 490 LazyMatcher(this._creator);
481 491
482 @override 492 @override
483 Description describe(Description description) { 493 Description describe(Description description) {
484 _createMatcher(); 494 _createMatcher();
485 return _wrappedMatcher.describe(description); 495 return _wrappedMatcher.describe(description);
486 } 496 }
487 497
488 @override 498 @override
489 Description describeMismatch(item, Description mismatchDescription, Map matchS tate, bool verbose) { 499 Description describeMismatch(item, Description mismatchDescription,
500 Map matchState, bool verbose) {
490 _createMatcher(); 501 _createMatcher();
491 return _wrappedMatcher.describeMismatch(item, mismatchDescription, matchStat e, verbose); 502 return _wrappedMatcher.describeMismatch(
503 item,
504 mismatchDescription,
505 matchState,
506 verbose);
492 } 507 }
493 508
494 @override 509 @override
495 bool matches(item, Map matchState) { 510 bool matches(item, Map matchState) {
496 _createMatcher(); 511 _createMatcher();
497 return _wrappedMatcher.matches(item, matchState); 512 return _wrappedMatcher.matches(item, matchState);
498 } 513 }
499 514
500 /** 515 /**
501 * Create the wrapped matcher object, if it hasn't been created already. 516 * Create the wrapped matcher object, if it hasn't been created already.
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 583
569 _MapOf(this.keyMatcher, this.valueMatcher); 584 _MapOf(this.keyMatcher, this.valueMatcher);
570 585
571 @override 586 @override
572 void populateMismatches(item, List<MismatchDescriber> mismatches) { 587 void populateMismatches(item, List<MismatchDescriber> mismatches) {
573 if (item is! Map) { 588 if (item is! Map) {
574 mismatches.add(simpleDescription('is not a map')); 589 mismatches.add(simpleDescription('is not a map'));
575 return; 590 return;
576 } 591 }
577 item.forEach((key, value) { 592 item.forEach((key, value) {
578 checkSubstructure(key, keyMatcher, mismatches, (Description description) 593 checkSubstructure(
579 => description.add('key ').addDescriptionOf(key)); 594 key,
580 checkSubstructure(value, valueMatcher, mismatches, (Description 595 keyMatcher,
581 description) => description.add('field ').addDescriptionOf(key)); 596 mismatches,
597 (Description description) => description.add('key ').addDescriptionOf( key));
598 checkSubstructure(
599 value,
600 valueMatcher,
601 mismatches,
602 (Description description) => description.add('field ').addDescriptionO f(key));
582 }); 603 });
583 } 604 }
584 605
585 @override 606 @override
586 Description describe(Description description) => description.add('Map from ' 607 Description describe(Description description) =>
587 ).addDescriptionOf(keyMatcher).add(' to ').addDescriptionOf(valueMatcher); 608 description.add(
609 'Map from ').addDescriptionOf(
610 keyMatcher).add(' to ').addDescriptionOf(valueMatcher);
588 } 611 }
589 612
590 Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) => new _MapOf( 613 Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) =>
591 keyMatcher, valueMatcher); 614 new _MapOf(keyMatcher, valueMatcher);
592 615
593 /** 616 /**
594 * Type of callbacks used to process notifications. 617 * Type of callbacks used to process notifications.
595 */ 618 */
596 typedef void NotificationProcessor(String event, params); 619 typedef void NotificationProcessor(String event, params);
597 620
598 /** 621 /**
599 * Instances of the class [Server] manage a connection to a server process, and 622 * Instances of the class [Server] manage a connection to a server process, and
600 * facilitate communication to and from the server. 623 * facilitate communication to and from the server.
601 */ 624 */
602 class Server { 625 class Server {
603 /** 626 /**
604 * Server process object, or null if server hasn't been started yet. 627 * Server process object, or null if server hasn't been started yet.
605 */ 628 */
606 Process _process = null; 629 Process _process = null;
607 630
608 /** 631 /**
609 * Commands that have been sent to the server but not yet acknowledged, and 632 * Commands that have been sent to the server but not yet acknowledged, and
610 * the [Completer] objects which should be completed when acknowledgement is 633 * the [Completer] objects which should be completed when acknowledgement is
611 * received. 634 * received.
612 */ 635 */
613 final HashMap<String, Completer> _pendingCommands = <String, Completer> {}; 636 final HashMap<String, Completer> _pendingCommands = <String, Completer>{};
614 637
615 /** 638 /**
616 * Number which should be used to compute the 'id' to send in the next command 639 * Number which should be used to compute the 'id' to send in the next command
617 * sent to the server. 640 * sent to the server.
618 */ 641 */
619 int _nextId = 0; 642 int _nextId = 0;
620 643
621 /** 644 /**
622 * [StreamController] to which notifications will be sent. 645 * [StreamController] to which notifications will be sent.
623 */ 646 */
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 */ 690 */
668 Future start(NotificationProcessor notificationProcessor, {bool debugServer: 691 Future start(NotificationProcessor notificationProcessor, {bool debugServer:
669 false}) { 692 false}) {
670 if (_process != null) { 693 if (_process != null) {
671 throw new Exception('Process already started'); 694 throw new Exception('Process already started');
672 } 695 }
673 _time.start(); 696 _time.start();
674 // TODO(paulberry): move the logic for finding the script, the dart 697 // TODO(paulberry): move the logic for finding the script, the dart
675 // executable, and the package root into a shell script. 698 // executable, and the package root into a shell script.
676 String dartBinary = Platform.executable; 699 String dartBinary = Platform.executable;
677 String rootDir = findRoot(Platform.script.toFilePath(windows: 700 String rootDir =
678 Platform.isWindows)); 701 findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
679 String serverPath = normalize(join(rootDir, 'bin', 'server.dart')); 702 String serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
680 List<String> arguments = []; 703 List<String> arguments = [];
681 if (debugServer) { 704 if (debugServer) {
682 arguments.add('--debug'); 705 arguments.add('--debug');
683 } 706 }
684 if (Platform.packageRoot.isNotEmpty) { 707 if (Platform.packageRoot.isNotEmpty) {
685 arguments.add('--package-root=${Platform.packageRoot}'); 708 arguments.add('--package-root=${Platform.packageRoot}');
686 } 709 }
687 arguments.add('--checked'); 710 arguments.add('--checked');
688 arguments.add(serverPath); 711 arguments.add(serverPath);
689 return Process.start(dartBinary, arguments).then((Process process) { 712 return Process.start(dartBinary, arguments).then((Process process) {
690 _process = process; 713 _process = process;
691 process.stdout.transform((new Utf8Codec()).decoder).transform( 714 process.stdout.transform(
692 new LineSplitter()).listen((String line) { 715 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((Strin g line) {
693 String trimmedLine = line.trim(); 716 String trimmedLine = line.trim();
694 _recordStdio('RECV: $trimmedLine'); 717 _recordStdio('RECV: $trimmedLine');
695 var message; 718 var message;
696 try { 719 try {
697 message = JSON.decoder.convert(trimmedLine); 720 message = JSON.decoder.convert(trimmedLine);
698 } catch (exception) { 721 } catch (exception) {
699 _badDataFromServer(); 722 _badDataFromServer();
700 return; 723 return;
701 } 724 }
702 expect(message, isMap); 725 expect(message, isMap);
703 Map messageAsMap = message; 726 Map messageAsMap = message;
704 if (messageAsMap.containsKey('id')) { 727 if (messageAsMap.containsKey('id')) {
705 expect(messageAsMap['id'], isString); 728 expect(messageAsMap['id'], isString);
706 String id = message['id']; 729 String id = message['id'];
707 Completer completer = _pendingCommands[id]; 730 Completer completer = _pendingCommands[id];
708 if (completer == null) { 731 if (completer == null) {
709 fail('Unexpected response from server: id=$id'); 732 fail('Unexpected response from server: id=$id');
710 } else { 733 } else {
711 _pendingCommands.remove(id); 734 _pendingCommands.remove(id);
712 } 735 }
713 if (messageAsMap.containsKey('error')) { 736 if (messageAsMap.containsKey('error')) {
714 // TODO(paulberry): propagate the error info to the completer. 737 // TODO(paulberry): propagate the error info to the completer.
715 completer.completeError(new UnimplementedError( 738 completer.completeError(
716 'Server responded with an error: ${JSON.encode(message)}')); 739 new UnimplementedError(
740 'Server responded with an error: ${JSON.encode(message)}'));
717 } else { 741 } else {
718 completer.complete(messageAsMap['result']); 742 completer.complete(messageAsMap['result']);
719 } 743 }
720 // Check that the message is well-formed. We do this after calling 744 // Check that the message is well-formed. We do this after calling
721 // completer.complete() or completer.completeError() so that we don't 745 // completer.complete() or completer.completeError() so that we don't
722 // stall the test in the event of an error. 746 // stall the test in the event of an error.
723 expect(message, isResponse); 747 expect(message, isResponse);
724 } else { 748 } else {
725 // Message is a notification. It should have an event and possibly 749 // Message is a notification. It should have an event and possibly
726 // params. 750 // params.
727 expect(messageAsMap, contains('event')); 751 expect(messageAsMap, contains('event'));
728 expect(messageAsMap['event'], isString); 752 expect(messageAsMap['event'], isString);
729 notificationProcessor(messageAsMap['event'], messageAsMap['params']); 753 notificationProcessor(messageAsMap['event'], messageAsMap['params']);
730 // Check that the message is well-formed. We do this after calling 754 // Check that the message is well-formed. We do this after calling
731 // notificationController.add() so that we don't stall the test in the 755 // notificationController.add() so that we don't stall the test in the
732 // event of an error. 756 // event of an error.
733 expect(message, isNotification); 757 expect(message, isNotification);
734 } 758 }
735 }); 759 });
736 process.stderr.transform((new Utf8Codec()).decoder).transform( 760 process.stderr.transform(
737 new LineSplitter()).listen((String line) { 761 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((Strin g line) {
738 String trimmedLine = line.trim(); 762 String trimmedLine = line.trim();
739 _recordStdio('ERR: $trimmedLine'); 763 _recordStdio('ERR: $trimmedLine');
740 _badDataFromServer(); 764 _badDataFromServer();
741 }); 765 });
742 process.exitCode.then((int code) { 766 process.exitCode.then((int code) {
743 _recordStdio('TERMINATED WITH EXIT CODE $code'); 767 _recordStdio('TERMINATED WITH EXIT CODE $code');
744 if (code != 0) { 768 if (code != 0) {
745 _badDataFromServer(); 769 _badDataFromServer();
746 } 770 }
747 }); 771 });
(...skipping 18 matching lines...) Expand all
766 /** 790 /**
767 * Send a command to the server. An 'id' will be automatically assigned. 791 * Send a command to the server. An 'id' will be automatically assigned.
768 * The returned [Future] will be completed when the server acknowledges the 792 * The returned [Future] will be completed when the server acknowledges the
769 * command with a response. If the server acknowledges the command with a 793 * command with a response. If the server acknowledges the command with a
770 * normal (non-error) response, the future will be completed with the 'result' 794 * normal (non-error) response, the future will be completed with the 'result'
771 * field from the response. If the server acknowledges the command with an 795 * field from the response. If the server acknowledges the command with an
772 * error response, the future will be completed with an error. 796 * error response, the future will be completed with an error.
773 */ 797 */
774 Future send(String method, Map<String, dynamic> params) { 798 Future send(String method, Map<String, dynamic> params) {
775 String id = '${_nextId++}'; 799 String id = '${_nextId++}';
776 Map<String, dynamic> command = <String, dynamic> { 800 Map<String, dynamic> command = <String, dynamic>{
777 'id': id, 801 'id': id,
778 'method': method 802 'method': method
779 }; 803 };
780 if (params != null) { 804 if (params != null) {
781 command['params'] = params; 805 command['params'] = params;
782 } 806 }
783 Completer completer = new Completer(); 807 Completer completer = new Completer();
784 _pendingCommands[id] = completer; 808 _pendingCommands[id] = completer;
785 String line = JSON.encode(command); 809 String line = JSON.encode(command);
786 _recordStdio('SEND: $line'); 810 _recordStdio('SEND: $line');
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 */ 852 */
829 void _recordStdio(String line) { 853 void _recordStdio(String line) {
830 double elapsedTime = _time.elapsedTicks / _time.frequency; 854 double elapsedTime = _time.elapsedTicks / _time.frequency;
831 line = "$elapsedTime: $line"; 855 line = "$elapsedTime: $line";
832 if (_debuggingStdio) { 856 if (_debuggingStdio) {
833 print(line); 857 print(line);
834 } 858 }
835 _recordedStdio.add(line); 859 _recordedStdio.add(line);
836 } 860 }
837 } 861 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698