Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 analyzer_cli.test.built_mode; | 5 library analyzer_cli.test.built_mode; |
| 6 | 6 |
| 7 import 'dart:collection'; | |
| 7 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 import 'dart:io'; | |
| 8 | 10 |
| 9 import 'package:analyzer_cli/src/build_mode.dart'; | 11 import 'package:analyzer_cli/src/build_mode.dart'; |
| 10 import 'package:analyzer_cli/src/driver.dart'; | 12 import 'package:analyzer_cli/src/driver.dart'; |
| 11 import 'package:analyzer_cli/src/options.dart'; | 13 import 'package:analyzer_cli/src/options.dart'; |
| 14 import 'package:analyzer_cli/src/worker_protocol.pb.dart'; | |
| 15 import 'package:protobuf/protobuf.dart'; | |
| 12 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 16 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 13 import 'package:typed_mock/typed_mock.dart'; | 17 import 'package:typed_mock/typed_mock.dart'; |
| 14 import 'package:unittest/unittest.dart'; | 18 import 'package:unittest/unittest.dart'; |
| 15 | 19 |
| 16 main() { | 20 main() { |
| 17 defineReflectiveTests(WorkerLoopTest); | 21 defineReflectiveTests(WorkerLoopTest); |
| 18 defineReflectiveTests(WorkInputTest); | |
| 19 defineReflectiveTests(WorkRequestTest); | |
| 20 } | 22 } |
| 21 | 23 |
| 22 typedef void _TestWorkerLoopAnalyze(CommandLineOptions options); | 24 typedef void _TestWorkerLoopAnalyze(CommandLineOptions options); |
| 23 | 25 |
| 24 @reflectiveTest | 26 @reflectiveTest |
| 25 class WorkerLoopTest { | 27 class WorkerLoopTest { |
| 26 final _TestWorkerConnection connection = new _TestWorkerConnection(); | 28 final _TestStdinStream stdinStream = new _TestStdinStream(); |
| 29 final _TestStdoutStream stdoutStream = new _TestStdoutStream(); | |
| 30 _TestWorkerConnection connection; | |
| 31 | |
| 32 WorkerLoopTest() { | |
| 33 connection = new _TestWorkerConnection(this.stdinStream, this.stdoutStream); | |
| 34 } | |
| 27 | 35 |
| 28 void setUp() {} | 36 void setUp() {} |
| 29 | 37 |
| 38 List<int> _serializeProto(GeneratedMessage message) { | |
| 39 var buffer = message.writeToBuffer(); | |
| 40 | |
| 41 var writer = new CodedBufferWriter(); | |
| 42 writer.writeInt32NoTag(buffer.length); | |
| 43 writer.writeRawBytes(buffer); | |
| 44 | |
| 45 return writer.toBuffer(); | |
| 46 } | |
| 47 | |
| 30 test_run() { | 48 test_run() { |
| 31 _setInputLine(JSON.encode({ | 49 var request = new WorkRequest(); |
| 32 'arguments': [ | 50 request.arguments.addAll([ |
| 33 '--build-summary-input=/tmp/1.sum', | 51 '--build-summary-input=/tmp/1.sum', |
| 34 '--build-summary-input=/tmp/2.sum', | 52 '--build-summary-input=/tmp/2.sum', |
| 35 'package:foo/foo.dart|/inputs/foo/lib/foo.dart', | 53 'package:foo/foo.dart|/inputs/foo/lib/foo.dart', |
| 36 'package:foo/bar.dart|/inputs/foo/lib/bar.dart' | 54 'package:foo/bar.dart|/inputs/foo/lib/bar.dart', |
| 37 ], | 55 ]); |
| 38 })); | 56 stdinStream.setInputBytes(_serializeProto(request)); |
| 57 | |
| 39 new _TestWorkerLoop(connection, (CommandLineOptions options) { | 58 new _TestWorkerLoop(connection, (CommandLineOptions options) { |
| 40 expect(options.buildSummaryInputs, | 59 expect(options.buildSummaryInputs, |
| 41 unorderedEquals(['/tmp/1.sum', '/tmp/2.sum'])); | 60 unorderedEquals(['/tmp/1.sum', '/tmp/2.sum'])); |
| 42 expect( | 61 expect( |
| 43 options.sourceFiles, | 62 options.sourceFiles, |
| 44 unorderedEquals([ | 63 unorderedEquals([ |
| 45 'package:foo/foo.dart|/inputs/foo/lib/foo.dart', | 64 'package:foo/foo.dart|/inputs/foo/lib/foo.dart', |
| 46 'package:foo/bar.dart|/inputs/foo/lib/bar.dart' | 65 'package:foo/bar.dart|/inputs/foo/lib/bar.dart' |
| 47 ])); | 66 ])); |
| 48 outSink.writeln('outSink a'); | 67 outSink.writeln('outSink a'); |
| 49 errorSink.writeln('errorSink a'); | 68 errorSink.writeln('errorSink a'); |
| 50 outSink.writeln('outSink b'); | 69 outSink.writeln('outSink b'); |
| 51 errorSink.writeln('errorSink b'); | 70 errorSink.writeln('errorSink b'); |
| 52 }).run(); | 71 }).run(); |
| 53 expect(connection.outputList, hasLength(1)); | 72 expect(connection.outputList, hasLength(1)); |
| 54 expect(connection.outputList[0], { | 73 |
| 55 'exit_code': WorkerLoop.EXIT_CODE_OK, | 74 var response = connection.outputList[0]; |
| 56 'output': allOf(contains('errorSink a'), contains('errorSink a'), | 75 expect(response.exitCode, WorkerLoop.EXIT_CODE_OK); |
| 57 contains('outSink a'), contains('outSink b')) | 76 expect( |
| 58 }); | 77 response.output, |
| 78 allOf(contains('errorSink a'), contains('errorSink a'), | |
| 79 contains('outSink a'), contains('outSink b'))); | |
| 80 | |
| 81 // Check that a serialized version was written to std out. | |
| 82 expect(stdoutStream.writes, hasLength(1)); | |
| 83 expect(stdoutStream.writes[0], _serializeProto(response)); | |
| 59 } | 84 } |
| 60 | 85 |
| 61 test_run_invalidOptions() { | 86 test_run_invalidOptions() { |
| 62 _setInputLine(JSON.encode({ | 87 var request = new WorkRequest(); |
| 63 'arguments': ['--unknown-option', '/foo.dart', '/bar.dart',], | 88 request.arguments.addAll(['--unknown-option', '/foo.dart', '/bar.dart']); |
| 64 })); | 89 stdinStream.setInputBytes(_serializeProto(request)); |
| 65 new _TestWorkerLoop(connection).run(); | 90 new _TestWorkerLoop(connection).run(); |
| 66 expect(connection.outputList, hasLength(1)); | 91 expect(connection.outputList, hasLength(1)); |
| 67 expect(connection.outputList[0], | 92 |
| 68 {'exit_code': WorkerLoop.EXIT_CODE_ERROR, 'output': anything}); | 93 var response = connection.outputList[0]; |
| 94 expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR); | |
| 95 expect(response.output, anything); | |
| 69 } | 96 } |
| 70 | 97 |
| 71 test_run_invalidRequest_noArgumentsInputs() { | 98 test_run_invalidRequest_noArgumentsInputs() { |
| 72 _setInputLine('{}'); | 99 stdinStream.setInputBytes(_serializeProto(new WorkRequest())); |
| 100 | |
| 73 new _TestWorkerLoop(connection).run(); | 101 new _TestWorkerLoop(connection).run(); |
| 74 expect(connection.outputList, hasLength(1)); | 102 expect(connection.outputList, hasLength(1)); |
| 75 expect(connection.outputList[0], | 103 |
| 76 {'exit_code': WorkerLoop.EXIT_CODE_ERROR, 'output': anything}); | 104 var response = connection.outputList[0]; |
| 105 expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR); | |
| 106 expect(response.output, anything); | |
| 77 } | 107 } |
| 78 | 108 |
| 79 test_run_invalidRequest_notJson() { | 109 test_run_invalidRequest_randomBytes() { |
| 80 _setInputLine('not a JSON string'); | 110 stdinStream.setInputBytes([1, 2, 3]); |
| 81 new _TestWorkerLoop(connection).run(); | 111 new _TestWorkerLoop(connection).run(); |
| 82 expect(connection.outputList, hasLength(1)); | 112 expect(connection.outputList, hasLength(1)); |
| 83 expect(connection.outputList[0], | 113 |
| 84 {'exit_code': WorkerLoop.EXIT_CODE_ERROR, 'output': anything}); | 114 var response = connection.outputList[0]; |
| 115 expect(response.exitCode, WorkerLoop.EXIT_CODE_ERROR); | |
| 116 expect(response.output, anything); | |
| 85 } | 117 } |
| 86 | 118 |
| 87 test_run_stopAtEOF() { | 119 test_run_stopAtEOF() { |
| 88 when(connection.readLineSync()).thenReturnList([null]); | 120 stdinStream.setInputBytes([-1]); |
| 89 new _TestWorkerLoop(connection).run(); | 121 new _TestWorkerLoop(connection).run(); |
| 90 } | 122 } |
| 91 | |
| 92 void _setInputLine(String line) { | |
| 93 when(connection.readLineSync()).thenReturnList([line, null]); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 @reflectiveTest | |
| 98 class WorkInputTest { | |
| 99 test_fromJson() { | |
| 100 WorkInput input = new WorkInput.fromJson({ | |
| 101 'path': '/my/path', | |
| 102 'digest': [1, 2, 3, 4, 5] | |
| 103 }); | |
| 104 expect(input.path, '/my/path'); | |
| 105 expect(input.digest, <int>[1, 2, 3, 4, 5]); | |
| 106 } | |
| 107 | |
| 108 test_fromJson_digest_isMissing() { | |
| 109 WorkInput input = new WorkInput.fromJson({'path': '/my/path',}); | |
| 110 expect(input.path, '/my/path'); | |
| 111 expect(input.digest, <int>[]); | |
| 112 } | |
| 113 | |
| 114 test_fromJson_digest_isNotList() { | |
| 115 expect(() { | |
| 116 new WorkInput.fromJson({'path': '/my/path', 'digest': 0}); | |
| 117 }, throwsArgumentError); | |
| 118 } | |
| 119 | |
| 120 test_fromJson_digest_isNotListOfInt() { | |
| 121 expect(() { | |
| 122 new WorkInput.fromJson({ | |
| 123 'path': '/my/path', | |
| 124 'digest': ['a', 'b', 'c'] | |
| 125 }); | |
| 126 }, throwsArgumentError); | |
| 127 } | |
| 128 | |
| 129 test_fromJson_path_isMissing() { | |
| 130 expect(() { | |
| 131 new WorkInput.fromJson({ | |
| 132 'digest': [1, 2, 3, 4, 5] | |
| 133 }); | |
| 134 }, throwsArgumentError); | |
| 135 } | |
| 136 | |
| 137 test_fromJson_path_isNotString() { | |
| 138 expect(() { | |
| 139 new WorkInput.fromJson({ | |
| 140 'path': 0, | |
| 141 'digest': [1, 2, 3, 4, 5] | |
| 142 }); | |
| 143 }, throwsArgumentError); | |
| 144 } | |
| 145 | |
| 146 test_toJson() { | |
| 147 WorkInput input = new WorkInput('/my/path', <int>[1, 2, 3, 4, 5]); | |
| 148 Map<String, Object> json = input.toJson(); | |
| 149 expect(json, { | |
| 150 'path': '/my/path', | |
| 151 'digest': [1, 2, 3, 4, 5] | |
| 152 }); | |
| 153 } | |
| 154 | |
| 155 test_toJson_withoutDigest() { | |
| 156 WorkInput input = new WorkInput('/my/path', null); | |
| 157 Map<String, Object> json = input.toJson(); | |
| 158 expect(json, {'path': '/my/path'}); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 @reflectiveTest | |
| 163 class WorkRequestTest { | |
| 164 test_fromJson() { | |
| 165 WorkRequest request = new WorkRequest.fromJson({ | |
| 166 'arguments': ['--arg1', '--arg2', '--arg3'], | |
| 167 'inputs': [ | |
| 168 { | |
| 169 'path': '/my/path1', | |
| 170 'digest': [11, 12, 13] | |
| 171 }, | |
| 172 { | |
| 173 'path': '/my/path2', | |
| 174 'digest': [21, 22, 23] | |
| 175 } | |
| 176 ] | |
| 177 }); | |
| 178 expect(request.arguments, ['--arg1', '--arg2', '--arg3']); | |
| 179 expect(request.inputs, hasLength(2)); | |
| 180 expect(request.inputs[0].path, '/my/path1'); | |
| 181 expect(request.inputs[0].digest, <int>[11, 12, 13]); | |
| 182 expect(request.inputs[1].path, '/my/path2'); | |
| 183 expect(request.inputs[1].digest, <int>[21, 22, 23]); | |
| 184 } | |
| 185 | |
| 186 test_fromJson_arguments_isMissing() { | |
| 187 WorkRequest request = new WorkRequest.fromJson({ | |
| 188 'inputs': [ | |
| 189 { | |
| 190 'path': '/my/path1', | |
| 191 'digest': [11, 12, 13] | |
| 192 }, | |
| 193 ] | |
| 194 }); | |
| 195 expect(request.arguments, isEmpty); | |
| 196 expect(request.inputs, hasLength(1)); | |
| 197 expect(request.inputs[0].path, '/my/path1'); | |
| 198 expect(request.inputs[0].digest, <int>[11, 12, 13]); | |
| 199 } | |
| 200 | |
| 201 test_fromJson_arguments_isNotList() { | |
| 202 expect(() { | |
| 203 new WorkRequest.fromJson({'arguments': 0, 'inputs': []}); | |
| 204 }, throwsArgumentError); | |
| 205 } | |
| 206 | |
| 207 test_fromJson_arguments_isNotListOfString() { | |
| 208 expect(() { | |
| 209 new WorkRequest.fromJson({ | |
| 210 'arguments': [0, 1, 2], | |
| 211 'inputs': [] | |
| 212 }); | |
| 213 }, throwsArgumentError); | |
| 214 } | |
| 215 | |
| 216 test_fromJson_inputs_isMissing() { | |
| 217 WorkRequest request = new WorkRequest.fromJson({ | |
| 218 'arguments': ['--arg1', '--arg2', '--arg3'], | |
| 219 }); | |
| 220 expect(request.arguments, ['--arg1', '--arg2', '--arg3']); | |
| 221 expect(request.inputs, hasLength(0)); | |
| 222 } | |
| 223 | |
| 224 test_fromJson_inputs_isNotList() { | |
| 225 expect(() { | |
| 226 new WorkRequest.fromJson({ | |
| 227 'arguments': ['--arg1', '--arg2', '--arg3'], | |
| 228 'inputs': 0 | |
| 229 }); | |
| 230 }, throwsArgumentError); | |
| 231 } | |
| 232 | |
| 233 test_fromJson_inputs_isNotListOfObject() { | |
| 234 expect(() { | |
| 235 new WorkRequest.fromJson({ | |
| 236 'arguments': ['--arg1', '--arg2', '--arg3'], | |
| 237 'inputs': [0, 1, 2] | |
| 238 }); | |
| 239 }, throwsArgumentError); | |
| 240 } | |
| 241 | |
| 242 test_fromJson_noArgumentsInputs() { | |
| 243 expect(() { | |
| 244 new WorkRequest.fromJson({}); | |
| 245 }, throwsArgumentError); | |
| 246 } | |
| 247 | |
| 248 test_toJson() { | |
| 249 WorkRequest request = new WorkRequest(<String>[ | |
| 250 '--arg1', | |
| 251 '--arg2', | |
| 252 '--arg3' | |
| 253 ], <WorkInput>[ | |
| 254 new WorkInput('/my/path1', <int>[11, 12, 13]), | |
| 255 new WorkInput('/my/path2', <int>[21, 22, 23]) | |
| 256 ]); | |
| 257 Map<String, Object> json = request.toJson(); | |
| 258 expect(json, { | |
| 259 'arguments': ['--arg1', '--arg2', '--arg3'], | |
| 260 'inputs': [ | |
| 261 { | |
| 262 'path': '/my/path1', | |
| 263 'digest': [11, 12, 13] | |
| 264 }, | |
| 265 { | |
| 266 'path': '/my/path2', | |
| 267 'digest': [21, 22, 23] | |
| 268 } | |
| 269 ] | |
| 270 }); | |
| 271 } | |
| 272 } | 123 } |
| 273 | 124 |
| 274 /** | 125 /** |
| 275 * [WorkerConnection] mock. | 126 * A [Stdin] mock. |
| 276 */ | 127 */ |
| 277 class _TestWorkerConnection extends TypedMock implements WorkerConnection { | 128 class _TestStdinStream extends TypedMock implements Stdin { |
| 278 final outputList = <Map<String, Object>>[]; | 129 final pendingBytes = new Queue<int>(); |
| 130 | |
| 131 // Sets all the input bytes for this stream, and simulates an EOF afterwords. | |
| 132 void setInputBytes(List<int> bytes) { | |
| 133 pendingBytes.addAll(bytes); | |
| 134 pendingBytes.add(-1); | |
|
Paul Berry
2016/04/06 19:54:19
It seems like this line is unnecessary, because re
jakemac
2016/04/06 20:18:30
Good point, I removed this and renamed it to `addI
| |
| 135 } | |
| 279 | 136 |
| 280 @override | 137 @override |
| 281 void writeJson(Map<String, Object> json) { | 138 int readByteSync() { |
| 282 outputList.add(json); | 139 if (pendingBytes.isEmpty) { |
| 140 return -1; | |
| 141 } else { | |
| 142 return pendingBytes.removeFirst(); | |
| 143 } | |
| 283 } | 144 } |
| 284 } | 145 } |
| 285 | 146 |
| 147 /** | |
| 148 * A [Stdout] mock. | |
| 149 */ | |
| 150 class _TestStdoutStream extends TypedMock implements Stdout { | |
| 151 final writes = <List<int>>[]; | |
| 152 | |
| 153 @override | |
| 154 void add(List<int> bytes) { | |
| 155 writes.add(bytes); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 /** | |
| 160 * A [StdWorkerConnection] which records its responses. | |
| 161 */ | |
| 162 class _TestWorkerConnection extends StdWorkerConnection { | |
| 163 final outputList = <WorkResponse>[]; | |
| 164 | |
| 165 _TestWorkerConnection(Stdin stdinStream, Stdout stdoutStream) | |
| 166 : super(stdinStream, stdoutStream); | |
| 167 | |
| 168 @override | |
| 169 void writeResponse(WorkResponse response) { | |
| 170 super.writeResponse(response); | |
| 171 outputList.add(response); | |
| 172 } | |
| 173 } | |
| 174 | |
| 286 /** | 175 /** |
| 287 * [WorkerLoop] for testing. | 176 * [WorkerLoop] for testing. |
| 288 */ | 177 */ |
| 289 class _TestWorkerLoop extends WorkerLoop { | 178 class _TestWorkerLoop extends WorkerLoop { |
| 290 final _TestWorkerLoopAnalyze _analyze; | 179 final _TestWorkerLoopAnalyze _analyze; |
| 291 | 180 |
| 292 _TestWorkerLoop(WorkerConnection connection, [this._analyze]) | 181 _TestWorkerLoop(WorkerConnection connection, [this._analyze]) |
| 293 : super(connection); | 182 : super(connection); |
| 294 | 183 |
| 295 @override | 184 @override |
| 296 void analyze(CommandLineOptions options) { | 185 void analyze(CommandLineOptions options) { |
| 297 if (_analyze != null) { | 186 if (_analyze != null) { |
| 298 _analyze(options); | 187 _analyze(options); |
| 299 } | 188 } |
| 300 } | 189 } |
| 301 } | 190 } |
| OLD | NEW |