OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library test.index.split_store; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:analysis_server/src/index/store/codec.dart'; | |
10 import 'package:analysis_server/src/index/store/split_store.dart'; | |
11 import 'package:analyzer/src/generated/element.dart'; | |
12 import 'package:analyzer/src/generated/engine.dart'; | |
13 import 'package:analyzer/src/generated/index.dart'; | |
14 import 'package:analyzer/src/generated/source.dart'; | |
15 import 'package:typed_mock/typed_mock.dart'; | |
16 import 'package:unittest/unittest.dart'; | |
17 | |
18 import '../../reflective_tests.dart'; | |
19 import 'memory_node_manager.dart'; | |
20 import 'single_source_container.dart'; | |
21 import 'typed_mocks.dart'; | |
22 | |
23 | |
24 main() { | |
25 groupSep = ' | '; | |
26 group('FileNodeManager', () { | |
27 runReflectiveTests(_FileNodeManagerTest); | |
28 }); | |
29 group('IndexNode', () { | |
30 runReflectiveTests(_IndexNodeTest); | |
31 }); | |
32 group('LocationData', () { | |
33 runReflectiveTests(_LocationDataTest); | |
34 }); | |
35 group('RelationKeyData', () { | |
36 runReflectiveTests(_RelationKeyDataTest); | |
37 }); | |
38 group('SplitIndexStore', () { | |
39 runReflectiveTests(_SplitIndexStoreTest); | |
40 }); | |
41 } | |
42 | |
43 | |
44 void _assertHasLocation(List<Location> locations, Element element, int offset, | |
45 int length) { | |
46 for (Location location in locations) { | |
47 if ((element == null || location.element == element) && location.offset == | |
48 offset && location.length == length) { | |
49 return; | |
50 } | |
51 } | |
52 fail('Expected to find Location' | |
53 '(element=$element, offset=$offset, length=$length)'); | |
54 } | |
55 | |
56 | |
57 @ReflectiveTestCase() | |
58 class _FileNodeManagerTest { | |
59 AnalysisContext context = new MockAnalysisContext('context'); | |
60 ContextCodec contextCodec = new MockContextCodec(); | |
61 int contextId = 13; | |
62 ElementCodec elementCodec = new MockElementCodec(); | |
63 FileManager fileManager = new _MockFileManager(); | |
64 MockLogger logger = new MockLogger(); | |
65 int nextElementId = 0; | |
66 FileNodeManager nodeManager; | |
67 RelationshipCodec relationshipCodec; | |
68 StringCodec stringCodec = new StringCodec(); | |
69 | |
70 void setUp() { | |
71 relationshipCodec = new RelationshipCodec(stringCodec); | |
72 nodeManager = new FileNodeManager(fileManager, logger, stringCodec, | |
73 contextCodec, elementCodec, relationshipCodec); | |
74 when(contextCodec.encode(context)).thenReturn(contextId); | |
75 when(contextCodec.decode(contextId)).thenReturn(context); | |
76 } | |
77 | |
78 void test_clear() { | |
79 nodeManager.clear(); | |
80 verify(fileManager.clear()).once(); | |
81 } | |
82 | |
83 void test_getLocationCount_empty() { | |
84 expect(nodeManager.locationCount, 0); | |
85 } | |
86 | |
87 void test_getNode_contextNull() { | |
88 String name = '42.index'; | |
89 // record bytes | |
90 List<int> bytes; | |
91 when(fileManager.write(name, anyObject)).thenInvoke((name, bs) { | |
92 bytes = bs; | |
93 }); | |
94 // put Node | |
95 Future putFuture; | |
96 { | |
97 IndexNode node = new IndexNode(context, elementCodec, relationshipCodec); | |
98 putFuture = nodeManager.putNode(name, node); | |
99 } | |
100 // do in the "put" Future | |
101 putFuture.then((_) { | |
102 // force "null" context | |
103 when(contextCodec.decode(contextId)).thenReturn(null); | |
104 // prepare input bytes | |
105 when(fileManager.read(name)).thenReturn(new Future.value(bytes)); | |
106 // get Node | |
107 return nodeManager.getNode(name).then((IndexNode node) { | |
108 expect(node, isNull); | |
109 // no exceptions | |
110 verifyZeroInteractions(logger); | |
111 }); | |
112 }); | |
113 } | |
114 | |
115 test_getNode_invalidVersion() { | |
116 String name = '42.index'; | |
117 // prepare a stream with an invalid version | |
118 when(fileManager.read(name)).thenReturn(new Future.value([0x01, 0x02, 0x03, | |
119 0x04])); | |
120 // do in the Future | |
121 return nodeManager.getNode(name).then((IndexNode node) { | |
122 // no IndexNode | |
123 expect(node, isNull); | |
124 // failed | |
125 verify(logger.logError2(anyObject, anyObject)).once(); | |
126 }); | |
127 } | |
128 | |
129 test_getNode_streamException() { | |
130 String name = '42.index'; | |
131 when(fileManager.read(name)).thenReturn(new Future(() { | |
132 return throw new Exception(); | |
133 })); | |
134 // do in the Future | |
135 return nodeManager.getNode(name).then((IndexNode node) { | |
136 expect(node, isNull); | |
137 // failed | |
138 verify(logger.logError2(anyString, anyObject)).once(); | |
139 }); | |
140 } | |
141 | |
142 test_getNode_streamNull() { | |
143 String name = '42.index'; | |
144 when(fileManager.read(name)).thenReturn(new Future.value(null)); | |
145 // do in the Future | |
146 return nodeManager.getNode(name).then((IndexNode node) { | |
147 expect(node, isNull); | |
148 // OK | |
149 verifyZeroInteractions(logger); | |
150 }); | |
151 } | |
152 | |
153 void test_newNode() { | |
154 IndexNode node = nodeManager.newNode(context); | |
155 expect(node.context, context); | |
156 expect(node.locationCount, 0); | |
157 } | |
158 | |
159 test_putNode_getNode() { | |
160 String name = '42.index'; | |
161 // record bytes | |
162 List<int> bytes; | |
163 when(fileManager.write(name, anyObject)).thenInvoke((name, bs) { | |
164 bytes = bs; | |
165 }); | |
166 // prepare elements | |
167 Element elementA = _mockElement(); | |
168 Element elementB = _mockElement(); | |
169 Element elementC = _mockElement(); | |
170 Relationship relationship = Relationship.getRelationship('my-relationship'); | |
171 // put Node | |
172 Future putFuture; | |
173 { | |
174 // prepare relations | |
175 int elementIdA = 0; | |
176 int elementIdB = 1; | |
177 int elementIdC = 2; | |
178 int relationshipId = relationshipCodec.encode(relationship); | |
179 RelationKeyData key = new RelationKeyData.forData(elementIdA, | |
180 relationshipId); | |
181 List<LocationData> locations = [new LocationData.forData(elementIdB, 1, | |
182 10), new LocationData.forData(elementIdC, 2, 20)]; | |
183 Map<RelationKeyData, List<LocationData>> relations = { | |
184 key: locations | |
185 }; | |
186 // prepare Node | |
187 IndexNode node = new _MockIndexNode(); | |
188 when(node.context).thenReturn(context); | |
189 when(node.relations).thenReturn(relations); | |
190 when(node.locationCount).thenReturn(2); | |
191 // put Node | |
192 putFuture = nodeManager.putNode(name, node); | |
193 } | |
194 // do in the Future | |
195 putFuture.then((_) { | |
196 // has locations | |
197 expect(nodeManager.locationCount, 2); | |
198 // prepare input bytes | |
199 when(fileManager.read(name)).thenReturn(new Future.value(bytes)); | |
200 // get Node | |
201 return nodeManager.getNode(name).then((IndexNode node) { | |
202 expect(2, node.locationCount); | |
203 { | |
204 List<Location> locations = node.getRelationships(elementA, | |
205 relationship); | |
206 expect(locations, hasLength(2)); | |
207 _assertHasLocation(locations, elementB, 1, 10); | |
208 _assertHasLocation(locations, elementC, 2, 20); | |
209 } | |
210 }); | |
211 }); | |
212 } | |
213 | |
214 test_putNode_streamException() { | |
215 String name = '42.index'; | |
216 Exception exception = new Exception(); | |
217 when(fileManager.write(name, anyObject)).thenReturn(new Future(() { | |
218 return throw exception; | |
219 })); | |
220 // prepare IndexNode | |
221 IndexNode node = new _MockIndexNode(); | |
222 when(node.context).thenReturn(context); | |
223 when(node.locationCount).thenReturn(0); | |
224 when(node.relations).thenReturn({}); | |
225 // try to put | |
226 return nodeManager.putNode(name, node).then((_) { | |
227 // failed | |
228 verify(logger.logError2(anyString, anyObject)).once(); | |
229 }); | |
230 } | |
231 | |
232 void test_removeNode() { | |
233 String name = '42.index'; | |
234 nodeManager.removeNode(name); | |
235 verify(fileManager.delete(name)).once(); | |
236 } | |
237 | |
238 Element _mockElement() { | |
239 int elementId = nextElementId++; | |
240 Element element = new MockElement(); | |
241 when(elementCodec.encode(element)).thenReturn(elementId); | |
242 when(elementCodec.decode(context, elementId)).thenReturn(element); | |
243 return element; | |
244 } | |
245 } | |
246 | |
247 | |
248 @ReflectiveTestCase() | |
249 class _IndexNodeTest { | |
250 AnalysisContext context = new MockAnalysisContext('context'); | |
251 ElementCodec elementCodec = new MockElementCodec(); | |
252 int nextElementId = 0; | |
253 IndexNode node; | |
254 RelationshipCodec relationshipCodec; | |
255 StringCodec stringCodec = new StringCodec(); | |
256 | |
257 void setUp() { | |
258 relationshipCodec = new RelationshipCodec(stringCodec); | |
259 node = new IndexNode(context, elementCodec, relationshipCodec); | |
260 } | |
261 | |
262 void test_getContext() { | |
263 expect(node.context, context); | |
264 } | |
265 | |
266 void test_recordRelationship() { | |
267 Element elementA = _mockElement(); | |
268 Element elementB = _mockElement(); | |
269 Element elementC = _mockElement(); | |
270 Relationship relationship = Relationship.getRelationship('my-relationship'); | |
271 Location locationA = new Location(elementB, 1, 2); | |
272 Location locationB = new Location(elementC, 10, 20); | |
273 // empty initially | |
274 expect(node.locationCount, 0); | |
275 // record | |
276 node.recordRelationship(elementA, relationship, locationA); | |
277 expect(node.locationCount, 1); | |
278 node.recordRelationship(elementA, relationship, locationB); | |
279 expect(node.locationCount, 2); | |
280 // get relations | |
281 expect(node.getRelationships(elementB, relationship), isEmpty); | |
282 { | |
283 List<Location> locations = node.getRelationships(elementA, relationship); | |
284 expect(locations, hasLength(2)); | |
285 _assertHasLocation(locations, null, 1, 2); | |
286 _assertHasLocation(locations, null, 10, 20); | |
287 } | |
288 // verify relations map | |
289 { | |
290 Map<RelationKeyData, List<LocationData>> relations = node.relations; | |
291 expect(relations, hasLength(1)); | |
292 List<LocationData> locations = relations.values.first; | |
293 expect(locations, hasLength(2)); | |
294 } | |
295 } | |
296 | |
297 void test_setRelations() { | |
298 Element elementA = _mockElement(); | |
299 Element elementB = _mockElement(); | |
300 Element elementC = _mockElement(); | |
301 Relationship relationship = Relationship.getRelationship('my-relationship'); | |
302 // record | |
303 { | |
304 int elementIdA = 0; | |
305 int elementIdB = 1; | |
306 int elementIdC = 2; | |
307 int relationshipId = relationshipCodec.encode(relationship); | |
308 RelationKeyData key = new RelationKeyData.forData(elementIdA, | |
309 relationshipId); | |
310 List<LocationData> locations = [new LocationData.forData(elementIdB, 1, | |
311 10), new LocationData.forData(elementIdC, 2, 20)]; | |
312 node.relations = { | |
313 key: locations | |
314 }; | |
315 } | |
316 // request | |
317 List<Location> locations = node.getRelationships(elementA, relationship); | |
318 expect(locations, hasLength(2)); | |
319 _assertHasLocation(locations, elementB, 1, 10); | |
320 _assertHasLocation(locations, elementC, 2, 20); | |
321 } | |
322 | |
323 Element _mockElement() { | |
324 int elementId = nextElementId++; | |
325 Element element = new MockElement(); | |
326 when(elementCodec.encode(element)).thenReturn(elementId); | |
327 when(elementCodec.decode(context, elementId)).thenReturn(element); | |
328 return element; | |
329 } | |
330 } | |
331 | |
332 | |
333 @ReflectiveTestCase() | |
334 class _LocationDataTest { | |
335 AnalysisContext context = new MockAnalysisContext('context'); | |
336 ElementCodec elementCodec = new MockElementCodec(); | |
337 StringCodec stringCodec = new StringCodec(); | |
338 | |
339 void test_newForData() { | |
340 Element element = new MockElement(); | |
341 when(elementCodec.decode(context, 0)).thenReturn(element); | |
342 LocationData locationData = new LocationData.forData(0, 1, 2); | |
343 Location location = locationData.getLocation(context, elementCodec); | |
344 expect(location.element, element); | |
345 expect(location.offset, 1); | |
346 expect(location.length, 2); | |
347 } | |
348 | |
349 void test_newForObject() { | |
350 // prepare Element | |
351 Element element = new MockElement(); | |
352 when(elementCodec.encode(element)).thenReturn(42); | |
353 when(elementCodec.decode(context, 42)).thenReturn(element); | |
354 // create | |
355 Location location = new Location(element, 1, 2); | |
356 LocationData locationData = new LocationData.forObject(elementCodec, | |
357 location); | |
358 // touch 'hashCode' | |
359 locationData.hashCode; | |
360 // == | |
361 expect(locationData == new LocationData.forData(42, 1, 2), isTrue); | |
362 // getLocation() | |
363 { | |
364 Location newLocation = locationData.getLocation(context, elementCodec); | |
365 expect(location.element, element); | |
366 expect(location.offset, 1); | |
367 expect(location.length, 2); | |
368 } | |
369 // no Element - no Location | |
370 { | |
371 when(elementCodec.decode(context, 42)).thenReturn(null); | |
372 Location newLocation = locationData.getLocation(context, elementCodec); | |
373 expect(newLocation, isNull); | |
374 } | |
375 } | |
376 } | |
377 | |
378 | |
379 /** | |
380 * [Location] has no [==] and [hashCode], so to compare locations by value we | |
381 * need to wrap them into such object. | |
382 */ | |
383 class _LocationEqualsWrapper { | |
384 final Location location; | |
385 | |
386 _LocationEqualsWrapper(this.location); | |
387 | |
388 @override | |
389 int get hashCode { | |
390 return 31 * (31 * location.element.hashCode + location.offset) + | |
391 location.length; | |
392 } | |
393 | |
394 @override | |
395 bool operator ==(Object other) { | |
396 if (other is _LocationEqualsWrapper) { | |
397 return other.location.offset == location.offset && other.location.length | |
398 == location.length && other.location.element == location.element; | |
399 } | |
400 return false; | |
401 } | |
402 } | |
403 | |
404 | |
405 class _MockFileManager extends TypedMock implements FileManager { | |
406 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | |
407 } | |
408 | |
409 | |
410 class _MockIndexNode extends TypedMock implements IndexNode { | |
411 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | |
412 } | |
413 | |
414 | |
415 @ReflectiveTestCase() | |
416 class _RelationKeyDataTest { | |
417 AnalysisContext context = new MockAnalysisContext('context'); | |
418 ElementCodec elementCodec = new MockElementCodec(); | |
419 RelationshipCodec relationshipCodec = new MockRelationshipCodec(); | |
420 StringCodec stringCodec = new StringCodec(); | |
421 | |
422 void test_newFromData() { | |
423 RelationKeyData keyData = new RelationKeyData.forData(1, 2); | |
424 // equals | |
425 expect(keyData == this, isFalse); | |
426 expect(keyData == new RelationKeyData.forData(10, 20), isFalse); | |
427 expect(keyData == keyData, isTrue); | |
428 expect(keyData == new RelationKeyData.forData(1, 2), isTrue); | |
429 } | |
430 | |
431 void test_newFromObjects() { | |
432 // prepare Element | |
433 Element element; | |
434 int elementId = 2; | |
435 { | |
436 element = new MockElement(); | |
437 ElementLocation location = new ElementLocationImpl.con3(['foo', 'bar']); | |
438 when(element.location).thenReturn(location); | |
439 when(context.getElement(location)).thenReturn(element); | |
440 when(elementCodec.encode(element)).thenReturn(elementId); | |
441 } | |
442 // prepare relationship | |
443 Relationship relationship = Relationship.getRelationship('my-relationship'); | |
444 int relationshipId = 1; | |
445 when(relationshipCodec.encode(relationship)).thenReturn(relationshipId); | |
446 // create RelationKeyData | |
447 RelationKeyData keyData = new RelationKeyData.forObject(elementCodec, | |
448 relationshipCodec, element, relationship); | |
449 // touch | |
450 keyData.hashCode; | |
451 // equals | |
452 expect(keyData == this, isFalse); | |
453 expect(keyData == new RelationKeyData.forData(10, 20), isFalse); | |
454 expect(keyData == keyData, isTrue); | |
455 expect(keyData == new RelationKeyData.forData(elementId, relationshipId), | |
456 isTrue); | |
457 } | |
458 } | |
459 | |
460 | |
461 | |
462 | |
463 @ReflectiveTestCase() | |
464 class _SplitIndexStoreTest { | |
465 AnalysisContext contextA = new MockAnalysisContext('contextA'); | |
466 | |
467 AnalysisContext contextB = new MockAnalysisContext('contextB'); | |
468 | |
469 AnalysisContext contextC = new MockAnalysisContext('contextC'); | |
470 | |
471 Element elementA = new MockElement('elementA'); | |
472 Element elementB = new MockElement('elementB'); | |
473 | |
474 Element elementC = new MockElement('elementC'); | |
475 Element elementD = new MockElement('elementD'); | |
476 ElementLocation elementLocationA = new ElementLocationImpl.con3( | |
477 ['/home/user/sourceA.dart', 'ClassA']); | |
478 ElementLocation elementLocationB = new ElementLocationImpl.con3( | |
479 ['/home/user/sourceB.dart', 'ClassB']); | |
480 ElementLocation elementLocationC = new ElementLocationImpl.con3( | |
481 ['/home/user/sourceC.dart', 'ClassC']); | |
482 ElementLocation elementLocationD = new ElementLocationImpl.con3( | |
483 ['/home/user/sourceD.dart', 'ClassD']); | |
484 HtmlElement htmlElementA = new MockHtmlElement(); | |
485 HtmlElement htmlElementB = new MockHtmlElement(); | |
486 LibraryElement libraryElement = new MockLibraryElement(); | |
487 Source librarySource = new MockSource('librarySource'); | |
488 CompilationUnitElement libraryUnitElement = new MockCompilationUnitElement(); | |
489 MemoryNodeManager nodeManager = new MemoryNodeManager(); | |
490 Relationship relationship = Relationship.getRelationship('test-relationship'); | |
491 Source sourceA = new MockSource('sourceA'); | |
492 Source sourceB = new MockSource('sourceB'); | |
493 Source sourceC = new MockSource('sourceC'); | |
494 Source sourceD = new MockSource('sourceD'); | |
495 SplitIndexStore store; | |
496 CompilationUnitElement unitElementA = new MockCompilationUnitElement(); | |
497 CompilationUnitElement unitElementB = new MockCompilationUnitElement(); | |
498 CompilationUnitElement unitElementC = new MockCompilationUnitElement(); | |
499 CompilationUnitElement unitElementD = new MockCompilationUnitElement(); | |
500 void setUp() { | |
501 store = new SplitIndexStore(nodeManager); | |
502 when(contextA.isDisposed).thenReturn(false); | |
503 when(contextB.isDisposed).thenReturn(false); | |
504 when(contextC.isDisposed).thenReturn(false); | |
505 when(contextA.getElement(elementLocationA)).thenReturn(elementA); | |
506 when(contextA.getElement(elementLocationB)).thenReturn(elementB); | |
507 when(contextA.getElement(elementLocationC)).thenReturn(elementC); | |
508 when(contextA.getElement(elementLocationD)).thenReturn(elementD); | |
509 when(sourceA.fullName).thenReturn('/home/user/sourceA.dart'); | |
510 when(sourceB.fullName).thenReturn('/home/user/sourceB.dart'); | |
511 when(sourceC.fullName).thenReturn('/home/user/sourceC.dart'); | |
512 when(sourceD.fullName).thenReturn('/home/user/sourceD.dart'); | |
513 when(elementA.context).thenReturn(contextA); | |
514 when(elementB.context).thenReturn(contextA); | |
515 when(elementC.context).thenReturn(contextA); | |
516 when(elementD.context).thenReturn(contextA); | |
517 when(elementA.location).thenReturn(elementLocationA); | |
518 when(elementB.location).thenReturn(elementLocationB); | |
519 when(elementC.location).thenReturn(elementLocationC); | |
520 when(elementD.location).thenReturn(elementLocationD); | |
521 when(elementA.enclosingElement).thenReturn(unitElementA); | |
522 when(elementB.enclosingElement).thenReturn(unitElementB); | |
523 when(elementC.enclosingElement).thenReturn(unitElementC); | |
524 when(elementD.enclosingElement).thenReturn(unitElementD); | |
525 when(elementA.source).thenReturn(sourceA); | |
526 when(elementB.source).thenReturn(sourceB); | |
527 when(elementC.source).thenReturn(sourceC); | |
528 when(elementD.source).thenReturn(sourceD); | |
529 when(elementA.library).thenReturn(libraryElement); | |
530 when(elementB.library).thenReturn(libraryElement); | |
531 when(elementC.library).thenReturn(libraryElement); | |
532 when(elementD.library).thenReturn(libraryElement); | |
533 when(unitElementA.source).thenReturn(sourceA); | |
534 when(unitElementB.source).thenReturn(sourceB); | |
535 when(unitElementC.source).thenReturn(sourceC); | |
536 when(unitElementD.source).thenReturn(sourceD); | |
537 when(unitElementA.library).thenReturn(libraryElement); | |
538 when(unitElementB.library).thenReturn(libraryElement); | |
539 when(unitElementC.library).thenReturn(libraryElement); | |
540 when(unitElementD.library).thenReturn(libraryElement); | |
541 when(htmlElementA.source).thenReturn(sourceA); | |
542 when(htmlElementB.source).thenReturn(sourceB); | |
543 // library | |
544 when(libraryUnitElement.library).thenReturn(libraryElement); | |
545 when(libraryUnitElement.source).thenReturn(librarySource); | |
546 when(libraryElement.source).thenReturn(librarySource); | |
547 when(libraryElement.definingCompilationUnit).thenReturn(libraryUnitElement); | |
548 } | |
549 | |
550 void test_aboutToIndexDart_disposedContext() { | |
551 when(contextA.isDisposed).thenReturn(true); | |
552 expect(store.aboutToIndexDart(contextA, unitElementA), isFalse); | |
553 } | |
554 | |
555 void test_aboutToIndexDart_disposedContext_wrapped() { | |
556 when(contextA.isDisposed).thenReturn(true); | |
557 InstrumentedAnalysisContextImpl instrumentedContext = | |
558 new MockInstrumentedAnalysisContextImpl(); | |
559 when(instrumentedContext.basis).thenReturn(contextA); | |
560 expect(store.aboutToIndexDart(instrumentedContext, unitElementA), isFalse); | |
561 } | |
562 | |
563 void test_aboutToIndexDart_library_first() { | |
564 when(libraryElement.parts).thenReturn(<CompilationUnitElement>[unitElementA, | |
565 unitElementB]); | |
566 { | |
567 store.aboutToIndexDart(contextA, libraryUnitElement); | |
568 store.doneIndex(); | |
569 } | |
570 { | |
571 List<Location> locations = store.getRelationships(elementA, relationship); | |
572 assertLocations(locations, []); | |
573 } | |
574 } | |
575 | |
576 test_aboutToIndexDart_library_secondWithoutOneUnit() { | |
577 Location locationA = mockLocation(elementA); | |
578 Location locationB = mockLocation(elementB); | |
579 { | |
580 store.aboutToIndexDart(contextA, unitElementA); | |
581 store.recordRelationship(elementA, relationship, locationA); | |
582 store.doneIndex(); | |
583 } | |
584 { | |
585 store.aboutToIndexDart(contextA, unitElementB); | |
586 store.recordRelationship(elementA, relationship, locationB); | |
587 store.doneIndex(); | |
588 } | |
589 // "A" and "B" locations | |
590 return store.getRelationshipsAsync(elementA, relationship).then( | |
591 (List<Location> locations) { | |
592 assertLocations(locations, [locationA, locationB]); | |
593 }).then((_) { | |
594 // apply "libraryUnitElement", only with "B" | |
595 when(libraryElement.parts).thenReturn([unitElementB]); | |
596 { | |
597 store.aboutToIndexDart(contextA, libraryUnitElement); | |
598 store.doneIndex(); | |
599 } | |
600 return store.getRelationshipsAsync(elementA, relationship).then( | |
601 (List<Location> locations) { | |
602 assertLocations(locations, [locationB]); | |
603 }); | |
604 }); | |
605 } | |
606 | |
607 void test_aboutToIndexDart_nullLibraryElement() { | |
608 when(unitElementA.library).thenReturn(null); | |
609 expect(store.aboutToIndexDart(contextA, unitElementA), isFalse); | |
610 } | |
611 | |
612 void test_aboutToIndexDart_nullLibraryUnitElement() { | |
613 when(libraryElement.definingCompilationUnit).thenReturn(null); | |
614 expect(store.aboutToIndexDart(contextA, unitElementA), isFalse); | |
615 } | |
616 | |
617 void test_aboutToIndexDart_nullUnitElement() { | |
618 expect(store.aboutToIndexDart(contextA, null), isFalse); | |
619 } | |
620 | |
621 test_aboutToIndexHtml_() { | |
622 Location locationA = mockLocation(elementA); | |
623 Location locationB = mockLocation(elementB); | |
624 { | |
625 store.aboutToIndexHtml(contextA, htmlElementA); | |
626 store.recordRelationship(elementA, relationship, locationA); | |
627 store.doneIndex(); | |
628 } | |
629 { | |
630 store.aboutToIndexHtml(contextA, htmlElementB); | |
631 store.recordRelationship(elementA, relationship, locationB); | |
632 store.doneIndex(); | |
633 } | |
634 // "A" and "B" locations | |
635 return store.getRelationshipsAsync(elementA, relationship).then( | |
636 (List<Location> locations) { | |
637 assertLocations(locations, [locationA, locationB]); | |
638 }); | |
639 } | |
640 | |
641 void test_aboutToIndexHtml_disposedContext() { | |
642 when(contextA.isDisposed).thenReturn(true); | |
643 expect(store.aboutToIndexHtml(contextA, htmlElementA), isFalse); | |
644 } | |
645 | |
646 void test_clear() { | |
647 Location locationA = mockLocation(elementA); | |
648 store.aboutToIndexDart(contextA, unitElementA); | |
649 store.recordRelationship(elementA, relationship, locationA); | |
650 store.doneIndex(); | |
651 expect(nodeManager.isEmpty(), isFalse); | |
652 // clear | |
653 store.clear(); | |
654 expect(nodeManager.isEmpty(), isTrue); | |
655 } | |
656 | |
657 test_getRelationships_empty() { | |
658 return store.getRelationshipsAsync(elementA, relationship).then( | |
659 (List<Location> locations) { | |
660 expect(locations, isEmpty); | |
661 }); | |
662 } | |
663 | |
664 void test_getStatistics() { | |
665 // empty initially | |
666 { | |
667 String statistics = store.statistics; | |
668 expect(statistics, contains('0 locations')); | |
669 expect(statistics, contains('0 sources')); | |
670 } | |
671 // add 2 locations | |
672 Location locationA = mockLocation(elementA); | |
673 Location locationB = mockLocation(elementB); | |
674 { | |
675 store.aboutToIndexDart(contextA, unitElementA); | |
676 store.recordRelationship(elementA, relationship, locationA); | |
677 store.doneIndex(); | |
678 } | |
679 { | |
680 store.aboutToIndexDart(contextA, unitElementB); | |
681 store.recordRelationship(elementA, relationship, locationB); | |
682 store.doneIndex(); | |
683 } | |
684 { | |
685 String statistics = store.statistics; | |
686 expect(statistics, contains('2 locations')); | |
687 expect(statistics, contains('3 sources')); | |
688 } | |
689 } | |
690 | |
691 void test_recordRelationship_nullElement() { | |
692 Location locationA = mockLocation(elementA); | |
693 store.recordRelationship(null, relationship, locationA); | |
694 store.doneIndex(); | |
695 expect(nodeManager.isEmpty(), isTrue); | |
696 } | |
697 | |
698 void test_recordRelationship_nullLocation() { | |
699 store.recordRelationship(elementA, relationship, null); | |
700 store.doneIndex(); | |
701 expect(nodeManager.isEmpty(), isTrue); | |
702 } | |
703 | |
704 test_recordRelationship_oneElement_twoNodes() { | |
705 Location locationA = mockLocation(elementA); | |
706 Location locationB = mockLocation(elementB); | |
707 { | |
708 store.aboutToIndexDart(contextA, unitElementA); | |
709 store.recordRelationship(elementA, relationship, locationA); | |
710 store.doneIndex(); | |
711 } | |
712 { | |
713 store.aboutToIndexDart(contextA, unitElementB); | |
714 store.recordRelationship(elementA, relationship, locationB); | |
715 store.doneIndex(); | |
716 } | |
717 return store.getRelationshipsAsync(elementA, relationship).then( | |
718 (List<Location> locations) { | |
719 assertLocations(locations, [locationA, locationB]); | |
720 }); | |
721 } | |
722 | |
723 test_recordRelationship_oneLocation() { | |
724 Location locationA = mockLocation(elementA); | |
725 store.aboutToIndexDart(contextA, unitElementA); | |
726 store.recordRelationship(elementA, relationship, locationA); | |
727 store.doneIndex(); | |
728 return store.getRelationshipsAsync(elementA, relationship).then( | |
729 (List<Location> locations) { | |
730 assertLocations(locations, [locationA]); | |
731 }); | |
732 } | |
733 | |
734 test_recordRelationship_twoLocations() { | |
735 Location locationA = mockLocation(elementA); | |
736 Location locationB = mockLocation(elementA); | |
737 store.aboutToIndexDart(contextA, unitElementA); | |
738 store.recordRelationship(elementA, relationship, locationA); | |
739 store.recordRelationship(elementA, relationship, locationB); | |
740 store.doneIndex(); | |
741 return store.getRelationshipsAsync(elementA, relationship).then( | |
742 (List<Location> locations) { | |
743 assertLocations(locations, [locationA, locationB]); | |
744 }); | |
745 } | |
746 | |
747 test_removeContext() { | |
748 Location locationA = mockLocation(elementA); | |
749 Location locationB = mockLocation(elementB); | |
750 { | |
751 store.aboutToIndexDart(contextA, unitElementA); | |
752 store.recordRelationship(elementA, relationship, locationA); | |
753 store.doneIndex(); | |
754 } | |
755 { | |
756 store.aboutToIndexDart(contextA, unitElementB); | |
757 store.recordRelationship(elementA, relationship, locationB); | |
758 store.doneIndex(); | |
759 } | |
760 // "A" and "B" locations | |
761 return store.getRelationshipsAsync(elementA, relationship).then( | |
762 (List<Location> locations) { | |
763 assertLocations(locations, [locationA, locationB]); | |
764 }).then((_) { | |
765 // remove "A" context | |
766 store.removeContext(contextA); | |
767 return store.getRelationshipsAsync(elementA, relationship).then( | |
768 (List<Location> locations) { | |
769 assertLocations(locations, []); | |
770 }); | |
771 }); | |
772 } | |
773 | |
774 void test_removeContext_nullContext() { | |
775 store.removeContext(null); | |
776 } | |
777 | |
778 test_removeSource_library() { | |
779 Location locationA = mockLocation(elementA); | |
780 Location locationB = mockLocation(elementB); | |
781 Location locationC = mockLocation(elementC); | |
782 { | |
783 store.aboutToIndexDart(contextA, unitElementA); | |
784 store.recordRelationship(elementA, relationship, locationA); | |
785 store.doneIndex(); | |
786 } | |
787 { | |
788 store.aboutToIndexDart(contextA, unitElementB); | |
789 store.recordRelationship(elementA, relationship, locationB); | |
790 store.doneIndex(); | |
791 } | |
792 { | |
793 store.aboutToIndexDart(contextA, unitElementC); | |
794 store.recordRelationship(elementA, relationship, locationC); | |
795 store.doneIndex(); | |
796 } | |
797 // "A", "B" and "C" locations | |
798 return store.getRelationshipsAsync(elementA, relationship).then( | |
799 (List<Location> locations) { | |
800 assertLocations(locations, [locationA, locationB, locationC]); | |
801 }).then((_) { | |
802 // remove "librarySource" | |
803 store.removeSource(contextA, librarySource); | |
804 return store.getRelationshipsAsync(elementA, relationship).then( | |
805 (List<Location> locations) { | |
806 assertLocations(locations, []); | |
807 }); | |
808 }); | |
809 } | |
810 | |
811 void test_removeSource_nullContext() { | |
812 store.removeSource(null, sourceA); | |
813 } | |
814 | |
815 test_removeSource_unit() { | |
816 Location locationA = mockLocation(elementA); | |
817 Location locationB = mockLocation(elementB); | |
818 Location locationC = mockLocation(elementC); | |
819 { | |
820 store.aboutToIndexDart(contextA, unitElementA); | |
821 store.recordRelationship(elementA, relationship, locationA); | |
822 store.doneIndex(); | |
823 } | |
824 { | |
825 store.aboutToIndexDart(contextA, unitElementB); | |
826 store.recordRelationship(elementA, relationship, locationB); | |
827 store.doneIndex(); | |
828 } | |
829 { | |
830 store.aboutToIndexDart(contextA, unitElementC); | |
831 store.recordRelationship(elementA, relationship, locationC); | |
832 store.doneIndex(); | |
833 } | |
834 // "A", "B" and "C" locations | |
835 return store.getRelationshipsAsync(elementA, relationship).then( | |
836 (List<Location> locations) { | |
837 assertLocations(locations, [locationA, locationB, locationC]); | |
838 }).then((_) { | |
839 // remove "A" source | |
840 store.removeSource(contextA, sourceA); | |
841 return store.getRelationshipsAsync(elementA, relationship).then( | |
842 (List<Location> locations) { | |
843 assertLocations(locations, [locationB, locationC]); | |
844 }); | |
845 }); | |
846 } | |
847 | |
848 test_removeSources_library() { | |
849 Location locationA = mockLocation(elementA); | |
850 Location locationB = mockLocation(elementB); | |
851 { | |
852 store.aboutToIndexDart(contextA, unitElementA); | |
853 store.recordRelationship(elementA, relationship, locationA); | |
854 store.doneIndex(); | |
855 } | |
856 { | |
857 store.aboutToIndexDart(contextA, unitElementB); | |
858 store.recordRelationship(elementA, relationship, locationB); | |
859 store.doneIndex(); | |
860 } | |
861 // "A" and "B" locations | |
862 return store.getRelationshipsAsync(elementA, relationship).then( | |
863 (List<Location> locations) { | |
864 assertLocations(locations, [locationA, locationB]); | |
865 }).then((_) { | |
866 // remove "librarySource" | |
867 store.removeSources(contextA, new SingleSourceContainer(librarySource)); | |
868 return store.getRelationshipsAsync(elementA, relationship).then( | |
869 (List<Location> locations) { | |
870 assertLocations(locations, []); | |
871 }); | |
872 }); | |
873 } | |
874 | |
875 void test_removeSources_nullContext() { | |
876 store.removeSources(null, null); | |
877 } | |
878 | |
879 test_removeSources_unit() { | |
880 Location locationA = mockLocation(elementA); | |
881 Location locationB = mockLocation(elementB); | |
882 Location locationC = mockLocation(elementC); | |
883 { | |
884 store.aboutToIndexDart(contextA, unitElementA); | |
885 store.recordRelationship(elementA, relationship, locationA); | |
886 store.doneIndex(); | |
887 } | |
888 { | |
889 store.aboutToIndexDart(contextA, unitElementB); | |
890 store.recordRelationship(elementA, relationship, locationB); | |
891 store.doneIndex(); | |
892 } | |
893 { | |
894 store.aboutToIndexDart(contextA, unitElementC); | |
895 store.recordRelationship(elementA, relationship, locationC); | |
896 store.doneIndex(); | |
897 } | |
898 // "A", "B" and "C" locations | |
899 return store.getRelationshipsAsync(elementA, relationship).then( | |
900 (List<Location> locations) { | |
901 assertLocations(locations, [locationA, locationB, locationC]); | |
902 }).then((_) { | |
903 // remove "A" source | |
904 store.removeSources(contextA, new SingleSourceContainer(sourceA)); | |
905 store.removeSource(contextA, sourceA); | |
906 return store.getRelationshipsAsync(elementA, relationship).then( | |
907 (List<Location> locations) { | |
908 assertLocations(locations, [locationB, locationC]); | |
909 }); | |
910 }); | |
911 } | |
912 | |
913 test_universe_aboutToIndex() { | |
914 when(contextA.getElement(elementLocationA)).thenReturn(elementA); | |
915 when(contextB.getElement(elementLocationB)).thenReturn(elementB); | |
916 Location locationA = mockLocation(elementA); | |
917 Location locationB = mockLocation(elementB); | |
918 { | |
919 store.aboutToIndexDart(contextA, unitElementA); | |
920 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
921 locationA); | |
922 store.doneIndex(); | |
923 } | |
924 { | |
925 store.aboutToIndexDart(contextB, unitElementB); | |
926 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
927 locationB); | |
928 store.doneIndex(); | |
929 } | |
930 // get relationships | |
931 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
932 relationship).then((List<Location> locations) { | |
933 assertLocations(locations, [locationA, locationB]); | |
934 }).then((_) { | |
935 // re-index "unitElementA" | |
936 store.aboutToIndexDart(contextA, unitElementA); | |
937 store.doneIndex(); | |
938 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
939 relationship).then((List<Location> locations) { | |
940 assertLocations(locations, [locationB]); | |
941 }); | |
942 }); | |
943 } | |
944 | |
945 test_universe_clear() { | |
946 when(contextA.getElement(elementLocationA)).thenReturn(elementA); | |
947 when(contextB.getElement(elementLocationB)).thenReturn(elementB); | |
948 Location locationA = mockLocation(elementA); | |
949 Location locationB = mockLocation(elementB); | |
950 { | |
951 store.aboutToIndexDart(contextA, unitElementA); | |
952 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
953 locationA); | |
954 store.doneIndex(); | |
955 } | |
956 { | |
957 store.aboutToIndexDart(contextA, unitElementB); | |
958 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
959 locationB); | |
960 store.doneIndex(); | |
961 } | |
962 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
963 relationship).then((List<Location> locations) { | |
964 assertLocations(locations, [locationA, locationB]); | |
965 }).then((_) { | |
966 // clear | |
967 store.clear(); | |
968 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
969 relationship).then((List<Location> locations) { | |
970 expect(locations, isEmpty); | |
971 }); | |
972 }); | |
973 } | |
974 | |
975 test_universe_removeContext() { | |
976 when(contextA.getElement(elementLocationA)).thenReturn(elementA); | |
977 when(contextB.getElement(elementLocationB)).thenReturn(elementB); | |
978 Location locationA = mockLocation(elementA); | |
979 Location locationB = mockLocation(elementB); | |
980 { | |
981 store.aboutToIndexDart(contextA, unitElementA); | |
982 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
983 locationA); | |
984 store.doneIndex(); | |
985 } | |
986 { | |
987 store.aboutToIndexDart(contextB, unitElementB); | |
988 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
989 locationB); | |
990 store.doneIndex(); | |
991 } | |
992 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
993 relationship).then((List<Location> locations) { | |
994 assertLocations(locations, [locationA, locationB]); | |
995 }).then((_) { | |
996 // remove "contextA" | |
997 store.removeContext(contextA); | |
998 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
999 relationship).then((List<Location> locations) { | |
1000 assertLocations(locations, [locationB]); | |
1001 }); | |
1002 }); | |
1003 } | |
1004 | |
1005 test_universe_removeSource() { | |
1006 when(contextA.getElement(elementLocationA)).thenReturn(elementA); | |
1007 when(contextB.getElement(elementLocationB)).thenReturn(elementB); | |
1008 Location locationA = mockLocation(elementA); | |
1009 Location locationB = mockLocation(elementB); | |
1010 { | |
1011 store.aboutToIndexDart(contextA, unitElementA); | |
1012 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
1013 locationA); | |
1014 store.doneIndex(); | |
1015 } | |
1016 { | |
1017 store.aboutToIndexDart(contextA, unitElementB); | |
1018 store.recordRelationship(UniverseElement.INSTANCE, relationship, | |
1019 locationB); | |
1020 store.doneIndex(); | |
1021 } | |
1022 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
1023 relationship).then((List<Location> locations) { | |
1024 assertLocations(locations, [locationA, locationB]); | |
1025 }).then((_) { | |
1026 // remove "sourceA" | |
1027 store.removeSource(contextA, sourceA); | |
1028 return store.getRelationshipsAsync(UniverseElement.INSTANCE, | |
1029 relationship).then((List<Location> locations) { | |
1030 assertLocations(locations, [locationB]); | |
1031 }); | |
1032 }); | |
1033 } | |
1034 | |
1035 /** | |
1036 * Asserts that the [actual] locations have all the [expected] locations and | |
1037 * only them. | |
1038 */ | |
1039 static void assertLocations(List<Location> actual, List<Location> expected) { | |
1040 List<_LocationEqualsWrapper> actualWrappers = wrapLocations(actual); | |
1041 List<_LocationEqualsWrapper> expectedWrappers = wrapLocations(expected); | |
1042 expect(actualWrappers, unorderedEquals(expectedWrappers)); | |
1043 } | |
1044 | |
1045 /** | |
1046 * @return the new [Location] mock. | |
1047 */ | |
1048 static Location mockLocation(Element element) { | |
1049 Location location = new MockLocation(); | |
1050 when(location.element).thenReturn(element); | |
1051 when(location.offset).thenReturn(0); | |
1052 when(location.length).thenReturn(0); | |
1053 return location; | |
1054 } | |
1055 | |
1056 /** | |
1057 * Wraps the given locations into [LocationEqualsWrapper]. | |
1058 */ | |
1059 static List<_LocationEqualsWrapper> wrapLocations(List<Location> locations) { | |
1060 List<_LocationEqualsWrapper> wrappers = <_LocationEqualsWrapper>[]; | |
1061 for (Location location in locations) { | |
1062 wrappers.add(new _LocationEqualsWrapper(location)); | |
1063 } | |
1064 return wrappers; | |
1065 } | |
1066 } | |
OLD | NEW |