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

Side by Side Diff: pkg/analyzer/test/src/dart/analysis/driver_test.dart

Issue 2450183004: More tests and a few fixed for the driver. (Closed)
Patch Set: Created 4 years, 1 month 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
« no previous file with comments | « pkg/analyzer/lib/src/dart/analysis/driver.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.test.driver; 5 library analyzer.test.driver;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert'; 8 import 'dart:convert';
9 9
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/error/error.dart'; 11 import 'package:analyzer/error/error.dart';
12 import 'package:analyzer/file_system/file_system.dart'; 12 import 'package:analyzer/file_system/file_system.dart';
13 import 'package:analyzer/file_system/memory_file_system.dart'; 13 import 'package:analyzer/file_system/memory_file_system.dart';
14 import 'package:analyzer/source/package_map_resolver.dart'; 14 import 'package:analyzer/source/package_map_resolver.dart';
15 import 'package:analyzer/src/dart/analysis/byte_store.dart'; 15 import 'package:analyzer/src/dart/analysis/byte_store.dart';
16 import 'package:analyzer/src/dart/analysis/driver.dart'; 16 import 'package:analyzer/src/dart/analysis/driver.dart';
17 import 'package:analyzer/src/error/codes.dart'; 17 import 'package:analyzer/src/error/codes.dart';
18 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; 18 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
19 import 'package:analyzer/src/generated/source.dart'; 19 import 'package:analyzer/src/generated/source.dart';
20 import 'package:async/async.dart';
21 import 'package:convert/convert.dart'; 20 import 'package:convert/convert.dart';
22 import 'package:crypto/crypto.dart'; 21 import 'package:crypto/crypto.dart';
23 import 'package:test/test.dart'; 22 import 'package:test/test.dart';
24 import 'package:test_reflective_loader/test_reflective_loader.dart'; 23 import 'package:test_reflective_loader/test_reflective_loader.dart';
25 24
26 import '../../context/mock_sdk.dart'; 25 import '../../context/mock_sdk.dart';
27 26
28 main() { 27 main() {
29 defineReflectiveSuite(() { 28 defineReflectiveSuite(() {
30 defineReflectiveTests(DriverTest); 29 defineReflectiveTests(DriverTest);
31 }); 30 });
32 } 31 }
33 32
33 /**
34 * Returns a [Future] that completes after pumping the event queue [times]
35 * times. By default, this should pump the event queue enough times to allow
36 * any code to run, as long as it's not waiting on some external event.
37 */
38 Future pumpEventQueue([int times = 5000]) {
39 if (times == 0) return new Future.value();
40 // We use a delayed future to allow microtask events to finish. The
41 // Future.value or Future() constructors use scheduleMicrotask themselves and
42 // would therefore not wait for microtask callbacks that are scheduled after
43 // invoking this method.
44 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1));
45 }
46
34 @reflectiveTest 47 @reflectiveTest
35 class DriverTest { 48 class DriverTest {
36 static final MockSdk sdk = new MockSdk(); 49 static final MockSdk sdk = new MockSdk();
37 50
38 final MemoryResourceProvider provider = new MemoryResourceProvider(); 51 final MemoryResourceProvider provider = new MemoryResourceProvider();
39 final ByteStore byteStore = new _TestByteStore(); 52 final ByteStore byteStore = new _TestByteStore();
40 final ContentCache contentCache = new ContentCache(); 53 final ContentCache contentCache = new ContentCache();
41 final StringBuffer logBuffer = new StringBuffer(); 54 final StringBuffer logBuffer = new StringBuffer();
42 55
43 AnalysisDriver driver; 56 AnalysisDriver driver;
44 StreamSplitter<AnalysisStatus> statusSplitter; 57 final _Monitor idleStatusMonitor = new _Monitor();
45 final List<AnalysisStatus> allStatuses = <AnalysisStatus>[]; 58 final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
46 final List<AnalysisResult> allResults = <AnalysisResult>[]; 59 final List<AnalysisResult> allResults = <AnalysisResult>[];
47 60
48 String testProject; 61 String testProject;
49 String testFile; 62 String testFile;
50 63
51 void setUp() { 64 void setUp() {
52 new MockSdk(); 65 new MockSdk();
53 testProject = _p('/test/lib'); 66 testProject = _p('/test/lib');
54 testFile = _p('/test/lib/test.dart'); 67 testFile = _p('/test/lib/test.dart');
55 driver = new AnalysisDriver( 68 driver = new AnalysisDriver(
56 new PerformanceLog(logBuffer), 69 new PerformanceLog(logBuffer),
57 provider, 70 provider,
58 byteStore, 71 byteStore,
59 contentCache, 72 contentCache,
60 new SourceFactory([ 73 new SourceFactory([
61 new DartUriResolver(sdk), 74 new DartUriResolver(sdk),
62 new PackageMapUriResolver(provider, <String, List<Folder>>{ 75 new PackageMapUriResolver(provider, <String, List<Folder>>{
63 'test': [provider.getFolder(testProject)] 76 'test': [provider.getFolder(testProject)]
64 }) 77 })
65 ], null, provider), 78 ], null, provider),
66 new AnalysisOptionsImpl()..strongMode = true); 79 new AnalysisOptionsImpl()..strongMode = true);
67 statusSplitter = new StreamSplitter(driver.status); 80 driver.status.lastWhere((status) {
68 statusSplitter.split().listen(allStatuses.add); 81 allStatuses.add(status);
82 if (status.isIdle) {
83 idleStatusMonitor.notify();
84 }
85 });
69 driver.results.listen(allResults.add); 86 driver.results.listen(allResults.add);
70 } 87 }
71 88
89 test_addFile_thenRemove() async {
90 var a = _p('/test/lib/a.dart');
91 var b = _p('/test/lib/b.dart');
92 provider.newFile(a, 'class A {}');
93 provider.newFile(b, 'class B {}');
94 driver.addFile(a);
95 driver.addFile(b);
96
97 // Now remove 'a'.
98 driver.removeFile(a);
99
100 await _waitForIdle();
101
102 // Only 'b' has been analyzed, because 'a' was removed before we started.
103 expect(allResults, hasLength(1));
104 expect(allResults[0].path, b);
105 }
106
107 test_changeFile_implicitlyAnalyzed() async {
108 var a = _p('/test/lib/a.dart');
109 var b = _p('/test/lib/b.dart');
110 provider.newFile(
111 a,
112 r'''
113 import 'b.dart';
114 var A = B;
115 ''');
116 provider.newFile(b, 'var B = 1;');
117
118 driver.priorityFiles = [a];
119 driver.addFile(a);
120
121 // We have a result only for "a".
122 await _waitForIdle();
123 expect(allResults, hasLength(1));
124 {
125 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
126 expect(_getTopLevelVarType(ar.unit, 'A'), 'int');
127 }
128 allResults.clear();
129
130 // Change "b" and notify.
131 provider.updateFile(b, 'var B = 1.2;');
132 driver.changeFile(b);
133
134 // While "b" is not analyzed explicitly, it is analyzed implicitly.
135 // The change causes "a" to be reanalyzed.
136 await _waitForIdle();
137 expect(allResults, hasLength(1));
138 {
139 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
140 expect(_getTopLevelVarType(ar.unit, 'A'), 'double');
141 }
142 }
143
144 test_changeFile_selfConsistent() async {
145 var a = _p('/test/lib/a.dart');
146 var b = _p('/test/lib/b.dart');
147 provider.newFile(
148 a,
149 r'''
150 import 'b.dart';
151 var A1 = 1;
152 var A2 = B1;
153 ''');
154 provider.newFile(
155 b,
156 r'''
157 import 'a.dart';
158 var B1 = A1;
159 ''');
160
161 driver.priorityFiles = [a, b];
162 driver.addFile(a);
163 driver.addFile(b);
164 await _waitForIdle();
165
166 // We have results for both "a" and "b".
167 expect(allResults, hasLength(2));
168 {
169 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
170 expect(_getTopLevelVarType(ar.unit, 'A1'), 'int');
171 expect(_getTopLevelVarType(ar.unit, 'A2'), 'int');
172 }
173 {
174 AnalysisResult br = allResults.firstWhere((r) => r.path == b);
175 expect(_getTopLevelVarType(br.unit, 'B1'), 'int');
176 }
177
178 // Clear the results and update "a".
179 allResults.clear();
180 provider.updateFile(
181 a,
182 r'''
183 import 'b.dart';
184 var A1 = 1.2;
185 var A2 = B1;
186 ''');
187 driver.changeFile(a);
188
189 // We again get results for both "a" and "b".
190 // The results are consistent.
191 await _waitForIdle();
192 expect(allResults, hasLength(2));
193 {
194 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
195 expect(_getTopLevelVarType(ar.unit, 'A1'), 'double');
196 expect(_getTopLevelVarType(ar.unit, 'A2'), 'double');
197 }
198 {
199 AnalysisResult br = allResults.firstWhere((r) => r.path == b);
200 expect(_getTopLevelVarType(br.unit, 'B1'), 'double');
201 }
202 }
203
204 test_changeFile_single() async {
205 _addTestFile('var V = 1;', priority: true);
206
207 // Initial analysis.
208 {
209 await _waitForIdle();
210 expect(allResults, hasLength(1));
211 AnalysisResult result = allResults[0];
212 expect(result.path, testFile);
213 expect(_getTopLevelVarType(result.unit, 'V'), 'int');
214 }
215
216 // Update the file, but don't notify the driver.
217 allResults.clear();
218 provider.updateFile(testFile, 'var V = 1.2');
219
220 // No new results.
221 await pumpEventQueue();
222 expect(allResults, isEmpty);
223
224 // Notify the driver about the change.
225 driver.changeFile(testFile);
226
227 // We get a new result.
228 {
229 await _waitForIdle();
230 expect(allResults, hasLength(1));
231 AnalysisResult result = allResults[0];
232 expect(result.path, testFile);
233 expect(_getTopLevelVarType(result.unit, 'V'), 'double');
234 }
235 }
236
72 test_getResult() async { 237 test_getResult() async {
73 String content = 'int f() => 42;'; 238 String content = 'int f() => 42;';
74 _addTestFile(content, priority: true); 239 _addTestFile(content, priority: true);
75 240
76 AnalysisResult result = await driver.getResult(testFile); 241 AnalysisResult result = await driver.getResult(testFile);
77 expect(result.path, testFile); 242 expect(result.path, testFile);
78 expect(result.uri.toString(), 'package:test/test.dart'); 243 expect(result.uri.toString(), 'package:test/test.dart');
79 expect(result.content, content); 244 expect(result.content, content);
80 expect(result.contentHash, _md5(content)); 245 expect(result.contentHash, _md5(content));
81 expect(result.unit, isNotNull); 246 expect(result.unit, isNotNull);
(...skipping 18 matching lines...) Expand all
100 { 265 {
101 AnalysisError error = result.errors[0]; 266 AnalysisError error = result.errors[0];
102 expect(error.offset, 13); 267 expect(error.offset, 13);
103 expect(error.length, 2); 268 expect(error.length, 2);
104 expect(error.errorCode, HintCode.UNUSED_LOCAL_VARIABLE); 269 expect(error.errorCode, HintCode.UNUSED_LOCAL_VARIABLE);
105 expect(error.message, "The value of the local variable 'vv' isn't used."); 270 expect(error.message, "The value of the local variable 'vv' isn't used.");
106 expect(error.correction, "Try removing the variable, or using it."); 271 expect(error.correction, "Try removing the variable, or using it.");
107 } 272 }
108 } 273 }
109 274
275 test_getResult_selfConsistent() async {
276 var a = _p('/test/lib/a.dart');
277 var b = _p('/test/lib/b.dart');
278 provider.newFile(
279 a,
280 r'''
281 import 'b.dart';
282 var A1 = 1;
283 var A2 = B1;
284 ''');
285 provider.newFile(
286 b,
287 r'''
288 import 'a.dart';
289 var B1 = A1;
290 ''');
291
292 driver.addFile(a);
293 driver.addFile(b);
294 await _waitForIdle();
295
296 {
297 AnalysisResult result = await driver.getResult(a);
298 expect(_getTopLevelVarType(result.unit, 'A1'), 'int');
299 expect(_getTopLevelVarType(result.unit, 'A2'), 'int');
300 }
301
302 // Update "a" that that "A1" is now "double".
Brian Wilkerson 2016/10/27 20:08:17 "that that"?
303 // Get result for "a".
304 //
305 // Even though we have not notified the driver about the change,
306 // we still get "double" for "A1", because getResult() re-read the content.
307 //
308 // We also get "double" for "A2", even though "A2" has the type from "b".
309 // That's because we check for "a" API signature consistency, and because
310 // it has changed, we invalidated the dependency cache, relinked libraries
311 // and recomputed types.
312 provider.updateFile(
313 a,
314 r'''
315 import 'b.dart';
316 var A1 = 1.2;
317 var A2 = B1;
318 ''');
319 {
320 AnalysisResult result = await driver.getResult(a);
321 expect(_getTopLevelVarType(result.unit, 'A1'), 'double');
322 expect(_getTopLevelVarType(result.unit, 'A2'), 'double');
323 }
324 }
325
326 test_getResult_thenRemove() async {
327 _addTestFile('main() {}', priority: true);
328
329 Future<AnalysisResult> resultFuture = driver.getResult(testFile);
330 driver.removeFile(testFile);
331
332 AnalysisResult result = await resultFuture;
333 expect(result, isNotNull);
334 expect(result.path, testFile);
335 expect(result.unit, isNotNull);
336 }
337
338 test_getResult_twoPendingFutures() async {
339 String content = 'main() {}';
340 _addTestFile(content, priority: true);
341
342 Future<AnalysisResult> future1 = driver.getResult(testFile);
343 Future<AnalysisResult> future2 = driver.getResult(testFile);
344
345 // Both futures complete, with the same result.
346 AnalysisResult result1 = await future1;
347 AnalysisResult result2 = await future2;
348 expect(result2, same(result1));
349 expect(result1.path, testFile);
350 expect(result1.unit, isNotNull);
351 }
352
353 test_removeFile_changeFile_implicitlyAnalyzed() async {
354 var a = _p('/test/lib/a.dart');
355 var b = _p('/test/lib/b.dart');
356 provider.newFile(
357 a,
358 r'''
359 import 'b.dart';
360 var A = B;
361 ''');
362 provider.newFile(b, 'var B = 1;');
363
364 driver.priorityFiles = [a, b];
365 driver.addFile(a);
366 driver.addFile(b);
367
368 // We have results for both "a" and "b".
369 await _waitForIdle();
370 expect(allResults, hasLength(2));
371 {
372 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
373 expect(_getTopLevelVarType(ar.unit, 'A'), 'int');
374 }
375 {
376 AnalysisResult br = allResults.firstWhere((r) => r.path == b);
377 expect(_getTopLevelVarType(br.unit, 'B'), 'int');
378 }
379 allResults.clear();
380
381 // Remove "b" and send the change notification.
382 provider.updateFile(b, 'var B = 1.2;');
383 driver.removeFile(b);
384 driver.changeFile(b);
385
386 // While "b" is not analyzed explicitly, it is analyzed implicitly.
387 // We don't get a result for "b".
388 // But the change causes "a" to be reanalyzed.
389 await _waitForIdle();
390 expect(allResults, hasLength(1));
391 {
392 AnalysisResult ar = allResults.firstWhere((r) => r.path == a);
393 expect(_getTopLevelVarType(ar.unit, 'A'), 'double');
394 }
395 }
396
397 test_removeFile_changeFile_notAnalyzed() async {
398 _addTestFile('main() {}');
399
400 // We have a result.
401 await _waitForIdle();
402 expect(allResults, hasLength(1));
403 expect(allResults[0].path, testFile);
404 allResults.clear();
405
406 // Remove the file and send the change notification.
407 // The change notification does nothing, because the file is explicitly
408 // or implicitly analyzed.
409 driver.removeFile(testFile);
410 driver.changeFile(testFile);
411
412 await _waitForIdle();
413 expect(allResults, isEmpty);
414 }
415
110 test_results_priority() async { 416 test_results_priority() async {
111 String content = 'int f() => 42;'; 417 String content = 'int f() => 42;';
112 _addTestFile(content, priority: true); 418 _addTestFile(content, priority: true);
113 419
114 await _waitForIdle(); 420 await _waitForIdle();
115 421
116 expect(allResults, hasLength(1)); 422 expect(allResults, hasLength(1));
117 AnalysisResult result = allResults.single; 423 AnalysisResult result = allResults.single;
118 expect(result.path, testFile); 424 expect(result.path, testFile);
119 expect(result.uri.toString(), 'package:test/test.dart'); 425 expect(result.uri.toString(), 'package:test/test.dart');
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 } 481 }
176 482
177 void _addTestFile(String content, {bool priority: false}) { 483 void _addTestFile(String content, {bool priority: false}) {
178 provider.newFile(testFile, content); 484 provider.newFile(testFile, content);
179 driver.addFile(testFile); 485 driver.addFile(testFile);
180 if (priority) { 486 if (priority) {
181 driver.priorityFiles = [testFile]; 487 driver.priorityFiles = [testFile];
182 } 488 }
183 } 489 }
184 490
491 VariableDeclaration _getTopLevelVar(CompilationUnit unit, String name) {
492 for (CompilationUnitMember declaration in unit.declarations) {
493 if (declaration is TopLevelVariableDeclaration) {
494 for (VariableDeclaration variable in declaration.variables.variables) {
495 if (variable.name.name == name) {
496 return variable;
497 }
498 }
499 }
500 }
501 fail('Cannot find the top-level variable $name in\n$unit');
502 return null;
503 }
504
505 String _getTopLevelVarType(CompilationUnit unit, String name) {
506 return _getTopLevelVar(unit, name).element.type.toString();
507 }
508
185 /** 509 /**
186 * Return the [provider] specific path for the given Posix [path]. 510 * Return the [provider] specific path for the given Posix [path].
187 */ 511 */
188 String _p(String path) => provider.convertPath(path); 512 String _p(String path) => provider.convertPath(path);
189 513
190 Future<Null> _waitForIdle() async { 514 Future<Null> _waitForIdle() async {
191 await statusSplitter.split().firstWhere((status) => status.isIdle); 515 await idleStatusMonitor.signal;
192 } 516 }
193 517
194 static String _md5(String content) { 518 static String _md5(String content) {
195 return hex.encode(md5.convert(UTF8.encode(content)).bytes); 519 return hex.encode(md5.convert(UTF8.encode(content)).bytes);
196 } 520 }
197 } 521 }
198 522
523 class _Monitor {
524 Completer<Null> _completer = new Completer<Null>();
525
526 Future<Null> get signal async {
527 await _completer.future;
528 _completer = new Completer<Null>();
529 }
530
531 void notify() {
532 if (!_completer.isCompleted) {
533 _completer.complete(null);
534 }
535 }
536 }
537
199 class _TestByteStore implements ByteStore { 538 class _TestByteStore implements ByteStore {
200 final map = <String, List<int>>{}; 539 final map = <String, List<int>>{};
201 540
202 @override 541 @override
203 List<int> get(String key) { 542 List<int> get(String key) {
204 return map[key]; 543 return map[key];
205 } 544 }
206 545
207 @override 546 @override
208 void put(String key, List<int> bytes) { 547 void put(String key, List<int> bytes) {
209 map[key] = bytes; 548 map[key] = bytes;
210 } 549 }
211 } 550 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/dart/analysis/driver.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698