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 |