| OLD | NEW |
| 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 22 matching lines...) Expand all Loading... |
| 33 optionalFields: {'result': anything, 'error': isRequestError}); | 33 optionalFields: {'result': anything, 'error': isRequestError}); |
| 34 | 34 |
| 35 Matcher isListOf(Matcher elementMatcher) => new _ListOf(elementMatcher); | 35 Matcher isListOf(Matcher elementMatcher) => new _ListOf(elementMatcher); |
| 36 | 36 |
| 37 Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) => | 37 Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) => |
| 38 new _MapOf(keyMatcher, valueMatcher); | 38 new _MapOf(keyMatcher, valueMatcher); |
| 39 | 39 |
| 40 Matcher isOneOf(List<Matcher> choiceMatchers) => new _OneOf(choiceMatchers); | 40 Matcher isOneOf(List<Matcher> choiceMatchers) => new _OneOf(choiceMatchers); |
| 41 | 41 |
| 42 /** | 42 /** |
| 43 * Assert that [actual] matches [matcher]. |
| 44 */ |
| 45 void outOfTestExpect(actual, matcher, |
| 46 {String reason, skip, bool verbose: false}) { |
| 47 var matchState = {}; |
| 48 try { |
| 49 if (matcher.matches(actual, matchState)) return; |
| 50 } catch (e, trace) { |
| 51 if (reason == null) { |
| 52 reason = '${(e is String) ? e : e.toString()} at $trace'; |
| 53 } |
| 54 } |
| 55 fail(_defaultFailFormatter(actual, matcher, reason, matchState, verbose)); |
| 56 } |
| 57 |
| 58 String _defaultFailFormatter( |
| 59 actual, Matcher matcher, String reason, Map matchState, bool verbose) { |
| 60 var description = new StringDescription(); |
| 61 description.add('Expected: ').addDescriptionOf(matcher).add('\n'); |
| 62 description.add(' Actual: ').addDescriptionOf(actual).add('\n'); |
| 63 |
| 64 var mismatchDescription = new StringDescription(); |
| 65 matcher.describeMismatch(actual, mismatchDescription, matchState, verbose); |
| 66 |
| 67 if (mismatchDescription.length > 0) { |
| 68 description.add(' Which: $mismatchDescription\n'); |
| 69 } |
| 70 if (reason != null) description.add(reason).add('\n'); |
| 71 return description.toString(); |
| 72 } |
| 73 |
| 74 /** |
| 43 * Type of closures used by LazyMatcher. | 75 * Type of closures used by LazyMatcher. |
| 44 */ | 76 */ |
| 45 typedef Matcher MatcherCreator(); | 77 typedef Matcher MatcherCreator(); |
| 46 | 78 |
| 47 /** | 79 /** |
| 48 * Type of closures used by MatchesJsonObject to record field mismatches. | 80 * Type of closures used by MatchesJsonObject to record field mismatches. |
| 49 */ | 81 */ |
| 50 typedef Description MismatchDescriber(Description mismatchDescription); | 82 typedef Description MismatchDescriber(Description mismatchDescription); |
| 51 | 83 |
| 52 /** | 84 /** |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 * The future will only be completed by 'server.status' notifications that are | 136 * The future will only be completed by 'server.status' notifications that are |
| 105 * received after this function call. So it is safe to use this getter | 137 * received after this function call. So it is safe to use this getter |
| 106 * multiple times in one test; each time it is used it will wait afresh for | 138 * multiple times in one test; each time it is used it will wait afresh for |
| 107 * analysis to finish. | 139 * analysis to finish. |
| 108 */ | 140 */ |
| 109 Future get analysisFinished { | 141 Future get analysisFinished { |
| 110 Completer completer = new Completer(); | 142 Completer completer = new Completer(); |
| 111 StreamSubscription subscription; | 143 StreamSubscription subscription; |
| 112 // This will only work if the caller has already subscribed to | 144 // This will only work if the caller has already subscribed to |
| 113 // SERVER_STATUS (e.g. using sendServerSetSubscriptions(['STATUS'])) | 145 // SERVER_STATUS (e.g. using sendServerSetSubscriptions(['STATUS'])) |
| 114 expect(_subscribedToServerStatus, isTrue); | 146 outOfTestExpect(_subscribedToServerStatus, isTrue); |
| 115 subscription = onServerStatus.listen((ServerStatusParams params) { | 147 subscription = onServerStatus.listen((ServerStatusParams params) { |
| 116 if (params.analysis != null && !params.analysis.isAnalyzing) { | 148 if (params.analysis != null && !params.analysis.isAnalyzing) { |
| 117 completer.complete(params); | 149 completer.complete(params); |
| 118 subscription.cancel(); | 150 subscription.cancel(); |
| 119 } | 151 } |
| 120 }); | 152 }); |
| 121 return completer.future; | 153 return completer.future; |
| 122 } | 154 } |
| 123 | 155 |
| 124 /** | 156 /** |
| (...skipping 15 matching lines...) Expand all Loading... |
| 140 * [sourceDirectory] is created. | 172 * [sourceDirectory] is created. |
| 141 */ | 173 */ |
| 142 Future setUp() { | 174 Future setUp() { |
| 143 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer'); | 175 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer'); |
| 144 | 176 |
| 145 onAnalysisErrors.listen((AnalysisErrorsParams params) { | 177 onAnalysisErrors.listen((AnalysisErrorsParams params) { |
| 146 currentAnalysisErrors[params.file] = params.errors; | 178 currentAnalysisErrors[params.file] = params.errors; |
| 147 }); | 179 }); |
| 148 Completer serverConnected = new Completer(); | 180 Completer serverConnected = new Completer(); |
| 149 onServerConnected.listen((_) { | 181 onServerConnected.listen((_) { |
| 150 expect(serverConnected.isCompleted, isFalse); | 182 outOfTestExpect(serverConnected.isCompleted, isFalse); |
| 151 serverConnected.complete(); | 183 serverConnected.complete(); |
| 152 }); | 184 }); |
| 153 onServerError.listen((ServerErrorParams params) { | 185 onServerError.listen((ServerErrorParams params) { |
| 154 // A server error should never happen during an integration test. | 186 // A server error should never happen during an integration test. |
| 155 fail('${params.message}\n${params.stackTrace}'); | 187 fail('${params.message}\n${params.stackTrace}'); |
| 156 }); | 188 }); |
| 157 return startServer().then((_) { | 189 return startServer().then((_) { |
| 158 server.listenToOutput(dispatchNotification); | 190 server.listenToOutput(dispatchNotification); |
| 159 server.exitCode.then((_) { | 191 server.exitCode.then((_) { |
| 160 skipShutdown = true; | 192 skipShutdown = true; |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 return; | 550 return; |
| 519 } | 551 } |
| 520 _recordStdio('RECV: $trimmedLine'); | 552 _recordStdio('RECV: $trimmedLine'); |
| 521 var message; | 553 var message; |
| 522 try { | 554 try { |
| 523 message = JSON.decoder.convert(trimmedLine); | 555 message = JSON.decoder.convert(trimmedLine); |
| 524 } catch (exception) { | 556 } catch (exception) { |
| 525 _badDataFromServer('JSON decode failure: $exception'); | 557 _badDataFromServer('JSON decode failure: $exception'); |
| 526 return; | 558 return; |
| 527 } | 559 } |
| 528 expect(message, isMap); | 560 outOfTestExpect(message, isMap); |
| 529 Map messageAsMap = message; | 561 Map messageAsMap = message; |
| 530 if (messageAsMap.containsKey('id')) { | 562 if (messageAsMap.containsKey('id')) { |
| 531 expect(messageAsMap['id'], isString); | 563 outOfTestExpect(messageAsMap['id'], isString); |
| 532 String id = message['id']; | 564 String id = message['id']; |
| 533 Completer completer = _pendingCommands[id]; | 565 Completer completer = _pendingCommands[id]; |
| 534 if (completer == null) { | 566 if (completer == null) { |
| 535 fail('Unexpected response from server: id=$id'); | 567 fail('Unexpected response from server: id=$id'); |
| 536 } else { | 568 } else { |
| 537 _pendingCommands.remove(id); | 569 _pendingCommands.remove(id); |
| 538 } | 570 } |
| 539 if (messageAsMap.containsKey('error')) { | 571 if (messageAsMap.containsKey('error')) { |
| 540 // TODO(paulberry): propagate the error info to the completer. | 572 // TODO(paulberry): propagate the error info to the completer. |
| 541 completer.completeError(new UnimplementedError( | 573 completer.completeError(new UnimplementedError( |
| 542 'Server responded with an error: ${JSON.encode(message)}')); | 574 'Server responded with an error: ${JSON.encode(message)}')); |
| 543 } else { | 575 } else { |
| 544 completer.complete(messageAsMap['result']); | 576 completer.complete(messageAsMap['result']); |
| 545 } | 577 } |
| 546 // Check that the message is well-formed. We do this after calling | 578 // Check that the message is well-formed. We do this after calling |
| 547 // completer.complete() or completer.completeError() so that we don't | 579 // completer.complete() or completer.completeError() so that we don't |
| 548 // stall the test in the event of an error. | 580 // stall the test in the event of an error. |
| 549 expect(message, isResponse); | 581 outOfTestExpect(message, isResponse); |
| 550 } else { | 582 } else { |
| 551 // Message is a notification. It should have an event and possibly | 583 // Message is a notification. It should have an event and possibly |
| 552 // params. | 584 // params. |
| 553 expect(messageAsMap, contains('event')); | 585 outOfTestExpect(messageAsMap, contains('event')); |
| 554 expect(messageAsMap['event'], isString); | 586 outOfTestExpect(messageAsMap['event'], isString); |
| 555 notificationProcessor(messageAsMap['event'], messageAsMap['params']); | 587 notificationProcessor(messageAsMap['event'], messageAsMap['params']); |
| 556 // Check that the message is well-formed. We do this after calling | 588 // Check that the message is well-formed. We do this after calling |
| 557 // notificationController.add() so that we don't stall the test in the | 589 // notificationController.add() so that we don't stall the test in the |
| 558 // event of an error. | 590 // event of an error. |
| 559 expect(message, isNotification); | 591 outOfTestExpect(message, isNotification); |
| 560 } | 592 } |
| 561 }); | 593 }); |
| 562 _process.stderr | 594 _process.stderr |
| 563 .transform((new Utf8Codec()).decoder) | 595 .transform((new Utf8Codec()).decoder) |
| 564 .transform(new LineSplitter()) | 596 .transform(new LineSplitter()) |
| 565 .listen((String line) { | 597 .listen((String line) { |
| 566 String trimmedLine = line.trim(); | 598 String trimmedLine = line.trim(); |
| 567 _recordStdio('ERR: $trimmedLine'); | 599 _recordStdio('ERR: $trimmedLine'); |
| 568 _badDataFromServer('Message received on stderr', silent: true); | 600 _badDataFromServer('Message received on stderr', silent: true); |
| 569 }); | 601 }); |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 920 void populateMismatches(item, List<MismatchDescriber> mismatches); | 952 void populateMismatches(item, List<MismatchDescriber> mismatches); |
| 921 | 953 |
| 922 /** | 954 /** |
| 923 * Create a [MismatchDescriber] describing a mismatch with a simple string. | 955 * Create a [MismatchDescriber] describing a mismatch with a simple string. |
| 924 */ | 956 */ |
| 925 MismatchDescriber simpleDescription(String description) => | 957 MismatchDescriber simpleDescription(String description) => |
| 926 (Description mismatchDescription) { | 958 (Description mismatchDescription) { |
| 927 mismatchDescription.add(description); | 959 mismatchDescription.add(description); |
| 928 }; | 960 }; |
| 929 } | 961 } |
| OLD | NEW |