blob: dc4a26200e4ce64398da1d5da39606ec0246c110 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library test.services.src.index.store.split_store;
import 'dart:async';
import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
import 'package:analysis_server/src/services/index/store/codec.dart';
import 'package:analysis_server/src/services/index/store/memory_node_manager.dart';
import 'package:analysis_server/src/services/index/store/split_store.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
import '../../../mocks.dart';
import '../../../utils.dart';
import 'mocks.dart';
import 'single_source_container.dart';
main() {
initializeTestEnvironment();
defineReflectiveTests(_FileNodeManagerTest);
defineReflectiveTests(_IndexNodeTest);
defineReflectiveTests(_LocationDataTest);
defineReflectiveTests(_RelationKeyDataTest);
defineReflectiveTests(_SplitIndexStoreTest);
}
void _assertHasLocation(List<LocationImpl> locations, IndexableElement element,
int offset, int length,
{bool isQualified: false, bool isResolved: true}) {
for (LocationImpl location in locations) {
if ((element == null || location.indexable == element) &&
location.offset == offset &&
location.length == length &&
location.isQualified == isQualified &&
location.isResolved == isResolved) {
return;
}
}
fail('Expected to find Location'
'(element=$element, offset=$offset, length=$length)');
}
void _assertHasLocationQ(List<LocationImpl> locations, IndexableElement element,
int offset, int length) {
_assertHasLocation(locations, element, offset, length, isQualified: true);
}
@reflectiveTest
class _FileNodeManagerTest {
MockLogger logger = new MockLogger();
StringCodec stringCodec = new StringCodec();
RelationshipCodec relationshipCodec;
AnalysisContext context = new MockAnalysisContext('context');
ContextCodec contextCodec = new MockContextCodec();
int contextId = 13;
ElementCodec elementCodec = new MockElementCodec();
int nextElementId = 0;
FileNodeManager nodeManager;
FileManager fileManager = new _MockFileManager();
void setUp() {
relationshipCodec = new RelationshipCodec(stringCodec);
nodeManager = new FileNodeManager(fileManager, logger, stringCodec,
contextCodec, elementCodec, relationshipCodec);
when(contextCodec.encode(context)).thenReturn(contextId);
when(contextCodec.decode(contextId)).thenReturn(context);
}
void test_clear() {
nodeManager.clear();
verify(fileManager.clear()).once();
}
void test_getLocationCount_empty() {
expect(nodeManager.locationCount, 0);
}
void test_getNode_contextNull() {
String name = '42.index';
// record bytes
List<int> bytes;
when(fileManager.write(name, anyObject)).thenInvoke((name, bs) {
bytes = bs;
});
// put Node
Future putFuture;
{
IndexNode node = new IndexNode(context, elementCodec, relationshipCodec);
putFuture = nodeManager.putNode(name, node);
}
// do in the "put" Future
putFuture.then((_) {
// force "null" context
when(contextCodec.decode(contextId)).thenReturn(null);
// prepare input bytes
when(fileManager.read(name)).thenReturn(new Future.value(bytes));
// get Node
return nodeManager.getNode(name).then((IndexNode node) {
expect(node, isNull);
// no exceptions
verifyZeroInteractions(logger);
});
});
}
test_getNode_invalidVersion() {
String name = '42.index';
// prepare a stream with an invalid version
when(fileManager.read(name))
.thenReturn(new Future.value([0x01, 0x02, 0x03, 0x04]));
// do in the Future
return nodeManager.getNode(name).then((IndexNode node) {
// no IndexNode
expect(node, isNull);
// failed
verify(logger.logError(anyObject, anyObject)).once();
});
}
test_getNode_streamException() {
String name = '42.index';
when(fileManager.read(name)).thenReturn(new Future(() {
return throw new Exception();
}));
// do in the Future
return nodeManager.getNode(name).then((IndexNode node) {
expect(node, isNull);
// failed
verify(logger.logError(anyString, anyObject)).once();
});
}
test_getNode_streamNull() {
String name = '42.index';
when(fileManager.read(name)).thenReturn(new Future.value(null));
// do in the Future
return nodeManager.getNode(name).then((IndexNode node) {
expect(node, isNull);
// OK
verifyZeroInteractions(logger);
});
}
void test_newNode() {
IndexNode node = nodeManager.newNode(context);
expect(node.context, context);
expect(node.locationCount, 0);
}
test_putNode_getNode() {
String name = '42.index';
// record bytes
List<int> bytes;
when(fileManager.write(name, anyObject)).thenInvoke((name, bs) {
bytes = bs;
});
// prepare elements
IndexableElement elementA = _mockElement();
IndexableElement elementB = _mockElement();
IndexableElement elementC = _mockElement();
RelationshipImpl relationship =
RelationshipImpl.getRelationship('my-relationship');
// put Node
Future putFuture;
{
// prepare relations
int relationshipId = relationshipCodec.encode(relationship);
RelationKeyData key =
new RelationKeyData.forData(0, 1, 2, relationshipId);
List<LocationData> locations = [
new LocationData.forData(3, 4, 5, 1, 10, 2),
new LocationData.forData(6, 7, 8, 2, 20, 3)
];
Map<RelationKeyData, List<LocationData>> relations = {key: locations};
// prepare Node
IndexNode node = new _MockIndexNode();
when(node.context).thenReturn(context);
when(node.relations).thenReturn(relations);
when(node.locationCount).thenReturn(2);
// put Node
putFuture = nodeManager.putNode(name, node);
}
// do in the Future
putFuture.then((_) {
// has locations
expect(nodeManager.locationCount, 2);
// prepare input bytes
when(fileManager.read(name)).thenReturn(new Future.value(bytes));
// get Node
return nodeManager.getNode(name).then((IndexNode node) {
expect(2, node.locationCount);
{
List<LocationImpl> locations =
node.getRelationships(elementA, relationship);
expect(locations, hasLength(2));
_assertHasLocation(locations, elementB, 1, 10);
_assertHasLocationQ(locations, elementC, 2, 20);
}
});
});
}
test_putNode_streamException() {
String name = '42.index';
Exception exception = new Exception();
when(fileManager.write(name, anyObject)).thenReturn(new Future(() {
return throw exception;
}));
// prepare IndexNode
IndexNode node = new _MockIndexNode();
when(node.context).thenReturn(context);
when(node.locationCount).thenReturn(0);
when(node.relations).thenReturn({});
// try to put
return nodeManager.putNode(name, node).then((_) {
// failed
verify(logger.logError(anyString, anyObject)).once();
});
}
void test_removeNode() {
String name = '42.index';
nodeManager.removeNode(name);
verify(fileManager.delete(name)).once();
}
IndexableElement _mockElement() {
int id1 = nextElementId++;
int id2 = nextElementId++;
int id3 = nextElementId++;
Element element = new MockElement();
IndexableObject indexable = new IndexableElement(element);
when(elementCodec.encode1(indexable)).thenReturn(id1);
when(elementCodec.encode2(indexable)).thenReturn(id2);
when(elementCodec.encode3(indexable)).thenReturn(id3);
when(elementCodec.decode(context, id1, id2, id3)).thenReturn(indexable);
return indexable;
}
}
@reflectiveTest
class _IndexNodeTest {
AnalysisContext context = new MockAnalysisContext('context');
ElementCodec elementCodec = new MockElementCodec();
int nextElementId = 0;
IndexNode node;
RelationshipCodec relationshipCodec;
StringCodec stringCodec = new StringCodec();
void setUp() {
relationshipCodec = new RelationshipCodec(stringCodec);
node = new IndexNode(context, elementCodec, relationshipCodec);
}
void test_getContext() {
expect(node.context, context);
}
void test_recordRelationship() {
IndexableElement elementA = _mockElement();
IndexableElement elementB = _mockElement();
IndexableElement elementC = _mockElement();
RelationshipImpl relationship =
RelationshipImpl.getRelationship('my-relationship');
LocationImpl locationA = new LocationImpl(elementB, 1, 2);
LocationImpl locationB = new LocationImpl(elementC, 10, 20);
// empty initially
expect(node.locationCount, 0);
// record
node.recordRelationship(elementA, relationship, locationA);
expect(node.locationCount, 1);
node.recordRelationship(elementA, relationship, locationB);
expect(node.locationCount, 2);
// get relations
expect(node.getRelationships(elementB, relationship), isEmpty);
{
List<LocationImpl> locations =
node.getRelationships(elementA, relationship);
expect(locations, hasLength(2));
_assertHasLocation(locations, null, 1, 2);
_assertHasLocation(locations, null, 10, 20);
}
// verify relations map
{
Map<RelationKeyData, List<LocationData>> relations = node.relations;
expect(relations, hasLength(1));
List<LocationData> locations = relations.values.first;
expect(locations, hasLength(2));
}
}
void test_setRelations() {
IndexableElement elementA = _mockElement();
IndexableElement elementB = _mockElement();
IndexableElement elementC = _mockElement();
RelationshipImpl relationship =
RelationshipImpl.getRelationship('my-relationship');
// record
{
int relationshipId = relationshipCodec.encode(relationship);
RelationKeyData key =
new RelationKeyData.forData(0, 1, 2, relationshipId);
List<LocationData> locations = [
new LocationData.forData(3, 4, 5, 1, 10, 2),
new LocationData.forData(6, 7, 8, 2, 20, 3)
];
node.relations = {key: locations};
}
// request
List<LocationImpl> locations =
node.getRelationships(elementA, relationship);
expect(locations, hasLength(2));
_assertHasLocation(locations, elementB, 1, 10);
_assertHasLocationQ(locations, elementC, 2, 20);
}
IndexableElement _mockElement() {
int id1 = nextElementId++;
int id2 = nextElementId++;
int id3 = nextElementId++;
Element element = new MockElement();
IndexableElement indexable = new IndexableElement(element);
when(elementCodec.encode1(indexable)).thenReturn(id1);
when(elementCodec.encode2(indexable)).thenReturn(id2);
when(elementCodec.encode3(indexable)).thenReturn(id3);
when(elementCodec.decode(context, id1, id2, id3)).thenReturn(indexable);
return indexable;
}
}
@reflectiveTest
class _LocationDataTest {
AnalysisContext context = new MockAnalysisContext('context');
ElementCodec elementCodec = new MockElementCodec();
StringCodec stringCodec = new StringCodec();
void test_newForData() {
Element element = new MockElement();
IndexableElement indexable = new IndexableElement(element);
when(elementCodec.decode(context, 11, 12, 13)).thenReturn(indexable);
LocationData locationData = new LocationData.forData(11, 12, 13, 1, 2, 0);
LocationImpl location = locationData.getLocation(context, elementCodec);
expect(location.indexable, indexable);
expect(location.offset, 1);
expect(location.length, 2);
expect(location.isQualified, isFalse);
expect(location.isResolved, isFalse);
}
void test_newForObject() {
// prepare Element
Element element = new MockElement();
IndexableElement indexable = new IndexableElement(element);
when(elementCodec.encode1(indexable)).thenReturn(11);
when(elementCodec.encode2(indexable)).thenReturn(12);
when(elementCodec.encode3(indexable)).thenReturn(13);
when(elementCodec.decode(context, 11, 12, 13)).thenReturn(indexable);
// create
LocationImpl location = new LocationImpl(indexable, 1, 2);
LocationData locationData =
new LocationData.forObject(elementCodec, location);
// touch 'hashCode'
locationData.hashCode;
// ==
expect(
locationData == new LocationData.forData(11, 12, 13, 1, 2, 2), isTrue);
// getLocation()
{
LocationImpl newLocation =
locationData.getLocation(context, elementCodec);
expect(newLocation.indexable, indexable);
expect(newLocation.offset, 1);
expect(newLocation.length, 2);
}
// no Element - no Location
{
when(elementCodec.decode(context, 11, 12, 13)).thenReturn(null);
LocationImpl newLocation =
locationData.getLocation(context, elementCodec);
expect(newLocation, isNull);
}
}
}
/**
* [LocationImpl] has no [==] and [hashCode], so to compare locations by value we
* need to wrap them into such object.
*/
class _LocationEqualsWrapper {
final LocationImpl location;
_LocationEqualsWrapper(this.location);
@override
int get hashCode {
return 31 * (31 * location.indexable.hashCode + location.offset) +
location.length;
}
@override
bool operator ==(Object other) {
if (other is _LocationEqualsWrapper) {
return other.location.offset == location.offset &&
other.location.length == location.length &&
other.location.indexable == location.indexable;
}
return false;
}
}
class _MockFileManager extends TypedMock implements FileManager {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class _MockIndexNode extends TypedMock implements IndexNode {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
@reflectiveTest
class _RelationKeyDataTest {
AnalysisContext context = new MockAnalysisContext('context');
ElementCodec elementCodec = new MockElementCodec();
RelationshipCodec relationshipCodec = new MockRelationshipCodec();
StringCodec stringCodec = new StringCodec();
void test_newFromData() {
RelationKeyData keyData = new RelationKeyData.forData(11, 12, 13, 2);
// equals
expect(keyData == this, isFalse);
expect(keyData == new RelationKeyData.forData(11, 12, 13, 20), isFalse);
expect(keyData == keyData, isTrue);
expect(keyData == new RelationKeyData.forData(11, 12, 13, 2), isTrue);
}
void test_newFromObjects() {
// prepare Element
IndexableElement indexable;
{
Element element = new MockElement();
indexable = new IndexableElement(element);
ElementLocation location = new ElementLocationImpl.con3(['foo', 'bar']);
when(element.location).thenReturn(location);
when(context.getElement(location)).thenReturn(indexable);
when(elementCodec.encode1(indexable)).thenReturn(11);
when(elementCodec.encode2(indexable)).thenReturn(12);
when(elementCodec.encode3(indexable)).thenReturn(13);
}
// prepare relationship
RelationshipImpl relationship =
RelationshipImpl.getRelationship('my-relationship');
int relationshipId = 1;
when(relationshipCodec.encode(relationship)).thenReturn(relationshipId);
// create RelationKeyData
RelationKeyData keyData = new RelationKeyData.forObject(
elementCodec, relationshipCodec, indexable, relationship);
// touch
keyData.hashCode;
// equals
expect(keyData == this, isFalse);
expect(keyData == new RelationKeyData.forData(11, 12, 13, 20), isFalse);
expect(keyData == keyData, isTrue);
expect(keyData == new RelationKeyData.forData(11, 12, 13, relationshipId),
isTrue);
}
}
@reflectiveTest
class _SplitIndexStoreTest {
AnalysisContext contextA = new MockAnalysisContext('contextA');
AnalysisContext contextB = new MockAnalysisContext('contextB');
AnalysisContext contextC = new MockAnalysisContext('contextC');
Element elementA = new MockElement('elementA');
Element elementB = new MockElement('elementB');
Element elementC = new MockElement('elementC');
Element elementD = new MockElement('elementD');
IndexableElement indexableA;
IndexableElement indexableB;
IndexableElement indexableC;
IndexableElement indexableD;
Source librarySource = new MockSource('librarySource');
CompilationUnitElement libraryUnitElement = new MockCompilationUnitElement();
LibraryElement libraryElement = new MockLibraryElement();
Source librarySourceB = new MockSource('librarySourceB');
LibraryElement libraryElementB = new MockLibraryElement();
CompilationUnitElement libraryUnitElementB = new MockCompilationUnitElement();
ElementCodec elementCodec = new MockElementCodec();
MemoryNodeManager nodeManager = new MemoryNodeManager();
RelationshipImpl relationship =
RelationshipImpl.getRelationship('test-relationship');
Source sourceA = new MockSource('sourceA');
Source sourceB = new MockSource('sourceB');
Source sourceC = new MockSource('sourceC');
Source sourceD = new MockSource('sourceD');
SplitIndexStore store;
CompilationUnitElement unitElementA = new MockCompilationUnitElement();
CompilationUnitElement unitElementB = new MockCompilationUnitElement();
CompilationUnitElement unitElementC = new MockCompilationUnitElement();
CompilationUnitElement unitElementD = new MockCompilationUnitElement();
void setUp() {
indexableA = new IndexableElement(elementA);
indexableB = new IndexableElement(elementB);
indexableC = new IndexableElement(elementC);
indexableD = new IndexableElement(elementD);
nodeManager.elementCodec = elementCodec;
store = new SplitIndexStore(
nodeManager, <IndexObjectManager>[new DartUnitIndexObjectManager()]);
when(elementCodec.encode1(indexableA)).thenReturn(11);
when(elementCodec.encode2(indexableA)).thenReturn(12);
when(elementCodec.encode3(indexableA)).thenReturn(13);
when(elementCodec.encode1(indexableB)).thenReturn(21);
when(elementCodec.encode2(indexableB)).thenReturn(22);
when(elementCodec.encode3(indexableB)).thenReturn(23);
when(elementCodec.encode1(indexableC)).thenReturn(31);
when(elementCodec.encode2(indexableC)).thenReturn(32);
when(elementCodec.encode3(indexableC)).thenReturn(33);
when(elementCodec.encode1(indexableD)).thenReturn(41);
when(elementCodec.encode2(indexableD)).thenReturn(42);
when(elementCodec.encode3(indexableD)).thenReturn(43);
when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(indexableA);
when(elementCodec.decode(contextA, 21, 22, 23)).thenReturn(indexableB);
when(elementCodec.decode(contextA, 31, 32, 33)).thenReturn(indexableC);
when(elementCodec.decode(contextA, 41, 42, 43)).thenReturn(indexableD);
when(contextA.isDisposed).thenReturn(false);
when(contextB.isDisposed).thenReturn(false);
when(contextC.isDisposed).thenReturn(false);
when(sourceA.fullName).thenReturn('/home/user/sourceA.dart');
when(sourceB.fullName).thenReturn('/home/user/sourceB.dart');
when(sourceC.fullName).thenReturn('/home/user/sourceC.dart');
when(sourceD.fullName).thenReturn('/home/user/sourceD.dart');
when(elementA.context).thenReturn(contextA);
when(elementB.context).thenReturn(contextA);
when(elementC.context).thenReturn(contextA);
when(elementD.context).thenReturn(contextA);
when(elementA.enclosingElement).thenReturn(unitElementA);
when(elementB.enclosingElement).thenReturn(unitElementB);
when(elementC.enclosingElement).thenReturn(unitElementC);
when(elementD.enclosingElement).thenReturn(unitElementD);
when(elementA.source).thenReturn(sourceA);
when(elementB.source).thenReturn(sourceB);
when(elementC.source).thenReturn(sourceC);
when(elementD.source).thenReturn(sourceD);
when(elementA.library).thenReturn(libraryElement);
when(elementB.library).thenReturn(libraryElement);
when(elementC.library).thenReturn(libraryElement);
when(elementD.library).thenReturn(libraryElement);
when(unitElementA.source).thenReturn(sourceA);
when(unitElementB.source).thenReturn(sourceB);
when(unitElementC.source).thenReturn(sourceC);
when(unitElementD.source).thenReturn(sourceD);
when(unitElementA.library).thenReturn(libraryElement);
when(unitElementB.library).thenReturn(libraryElement);
when(unitElementC.library).thenReturn(libraryElement);
when(unitElementD.library).thenReturn(libraryElement);
// library
when(librarySource.fullName).thenReturn('/home/user/librarySource.dart');
when(libraryUnitElement.library).thenReturn(libraryElement);
when(libraryUnitElement.source).thenReturn(librarySource);
when(libraryElement.source).thenReturn(librarySource);
when(libraryElement.definingCompilationUnit).thenReturn(libraryUnitElement);
// library B
when(librarySourceB.fullName).thenReturn('/home/user/librarySource.dart');
when(libraryUnitElementB.library).thenReturn(libraryElementB);
when(libraryUnitElementB.source).thenReturn(librarySourceB);
when(libraryElementB.source).thenReturn(librarySourceB);
when(libraryElementB.definingCompilationUnit)
.thenReturn(libraryUnitElementB);
}
void test_aboutToIndexDart_disposedContext() {
when(contextA.isDisposed).thenReturn(true);
expect(store.aboutToIndex(contextA, unitElementA), isFalse);
}
Future test_aboutToIndexDart_library_first() {
when(libraryElement.parts)
.thenReturn(<CompilationUnitElement>[unitElementA, unitElementB]);
{
store.aboutToIndex(contextA, libraryUnitElement);
store.doneIndex();
}
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, []);
});
}
test_aboutToIndexDart_library_secondWithoutOneUnit() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
// "A" and "B" locations
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB]);
// apply "libraryUnitElement", only with "B"
when(libraryElement.parts).thenReturn([unitElementB]);
{
store.aboutToIndex(contextA, libraryUnitElement);
store.doneIndex();
}
}).then((_) {
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationB]);
});
});
}
void test_aboutToIndexDart_nullLibraryElement() {
when(unitElementA.library).thenReturn(null);
expect(store.aboutToIndex(contextA, unitElementA), isFalse);
}
void test_aboutToIndexDart_nullLibraryUnitElement() {
when(libraryElement.definingCompilationUnit).thenReturn(null);
expect(store.aboutToIndex(contextA, unitElementA), isFalse);
}
void test_aboutToIndexDart_nullUnitElement() {
expect(store.aboutToIndex(contextA, null), isFalse);
}
test_cancelIndexDart() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableA);
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.recordRelationship(indexableA, relationship, locationB);
store.recordTopLevelDeclaration(elementA);
store.cancelIndex();
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, []);
expect(store.getTopLevelDeclarations((name) => true), isEmpty);
});
}
void test_clear() {
LocationImpl locationA = mockLocation(indexableA);
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
expect(nodeManager.isEmpty(), isFalse);
// clear
store.clear();
expect(nodeManager.isEmpty(), isTrue);
}
test_getRelationships_empty() {
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
expect(locations, isEmpty);
});
}
void test_getStatistics() {
// empty initially
{
String statistics = store.statistics;
expect(statistics, contains('0 locations'));
expect(statistics, contains('0 sources'));
}
// add 2 locations
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
{
String statistics = store.statistics;
expect(statistics, contains('2 locations'));
expect(statistics, contains('3 sources'));
}
}
void test_recordRelationship_multiplyDefinedElement() {
Element multiplyElement =
new MultiplyDefinedElementImpl(contextA, <Element>[elementA, elementB]);
LocationImpl location = mockLocation(indexableA);
store.recordRelationship(
new IndexableElement(multiplyElement), relationship, location);
store.doneIndex();
expect(nodeManager.isEmpty(), isTrue);
}
void test_recordRelationship_nullElement() {
LocationImpl locationA = mockLocation(indexableA);
store.recordRelationship(null, relationship, locationA);
store.doneIndex();
expect(nodeManager.isEmpty(), isTrue);
}
void test_recordRelationship_nullLocation() {
store.recordRelationship(indexableA, relationship, null);
store.doneIndex();
expect(nodeManager.isEmpty(), isTrue);
}
test_recordRelationship_oneElement_twoNodes() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB]);
});
}
test_recordRelationship_oneLocation() {
LocationImpl locationA = mockLocation(indexableA);
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA]);
});
}
test_recordRelationship_twoLocations() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableA);
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB]);
});
}
test_removeContext() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
// "A" and "B" locations
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB]);
// remove "A" context
store.removeContext(contextA);
}).then((_) {
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, []);
});
});
}
void test_removeContext_nullContext() {
store.removeContext(null);
}
test_removeSource_library() async {
when(elementB.library).thenReturn(libraryElementB);
when(unitElementB.library).thenReturn(libraryElementB);
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
LocationImpl locationC = mockLocation(indexableC);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableD, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableD, relationship, locationB);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementC);
store.recordRelationship(indexableD, relationship, locationC);
store.doneIndex();
}
// "A", "B" and "C" locations
{
var locations = await store.getRelationships(indexableD, relationship);
assertLocations(locations, [locationA, locationB, locationC]);
}
// remove "librarySource"
store.removeSource(contextA, librarySource);
// only "B" location, which is in "librarySourceB"
{
var locations = await store.getRelationships(indexableD, relationship);
assertLocations(locations, [locationB]);
}
}
void test_removeSource_nullContext() {
store.removeSource(null, sourceA);
}
test_removeSource_unit() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
LocationImpl locationC = mockLocation(indexableC);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementC);
store.recordRelationship(indexableA, relationship, locationC);
store.doneIndex();
}
// "A", "B" and "C" locations
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB, locationC]);
}).then((_) {
// remove "A" source
store.removeSource(contextA, sourceA);
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationB, locationC]);
});
});
}
test_removeSources_library() {
LocationImpl locationA = mockLocation(indexableA);
LocationImpl locationB = mockLocation(indexableB);
{
store.aboutToIndex(contextA, unitElementA);
store.recordRelationship(indexableA, relationship, locationA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordRelationship(indexableA, relationship, locationB);
store.doneIndex();
}
// "A" and "B" locations
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, [locationA, locationB]);
}).then((_) {
// remove "librarySource"
store.removeSources(contextA, new SingleSourceContainer(librarySource));
return store
.getRelationships(indexableA, relationship)
.then((List<LocationImpl> locations) {
assertLocations(locations, []);
});
});
}
void test_removeSources_nullContext() {
store.removeSources(null, null);
}
void test_removeSources_unit() {
{
store.aboutToIndex(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementB);
store.recordTopLevelDeclaration(elementB);
store.doneIndex();
}
{
store.aboutToIndex(contextA, unitElementC);
store.recordTopLevelDeclaration(elementC);
store.doneIndex();
}
// A, B, C elements
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementA, elementB, elementC]));
}
// remove "A" source
store.removeSources(contextA, new SingleSourceContainer(sourceA));
store.removeSource(contextA, sourceA);
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementB, elementC]));
}
}
void test_universe_aboutToIndex() {
when(elementCodec.decode(contextA, 11, 12, 13))
.thenReturn(new IndexableElement(elementA));
when(elementCodec.decode(contextB, 21, 22, 23))
.thenReturn(new IndexableElement(elementB));
{
store.aboutToIndex(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
store.doneIndex();
}
{
store.aboutToIndex(contextB, unitElementB);
store.recordTopLevelDeclaration(elementB);
store.doneIndex();
}
// elementA, elementB
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementA, elementB]));
}
// re-index "unitElementA"
{
store.aboutToIndex(contextA, unitElementA);
store.doneIndex();
}
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementB]));
}
}
void test_universe_clear() {
when(elementCodec.decode(contextA, 11, 12, 13))
.thenReturn(new IndexableElement(elementA));
when(elementCodec.decode(contextB, 21, 22, 23))
.thenReturn(new IndexableElement(elementB));
{
store.aboutToIndex(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
store.doneIndex();
}
{
store.aboutToIndex(contextB, unitElementB);
store.recordTopLevelDeclaration(elementB);
store.doneIndex();
}
// elementA, elementB
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementA, elementB]));
}
// clear
store.clear();
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, isEmpty);
}
}
void test_universe_removeContext() {
when(elementCodec.decode(contextA, 11, 12, 13))
.thenReturn(new IndexableElement(elementA));
when(elementCodec.decode(contextB, 21, 22, 23))
.thenReturn(new IndexableElement(elementB));
{
store.aboutToIndex(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
store.doneIndex();
}
{
store.aboutToIndex(contextB, unitElementB);
store.recordTopLevelDeclaration(elementB);
store.doneIndex();
}
// elementA, elementB
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementA, elementB]));
}
// remove "contextA"
store.removeContext(contextA);
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementB]));
}
}
void test_universe_removeSource() {
when(elementCodec.decode(contextA, 11, 12, 13))
.thenReturn(new IndexableElement(elementA));
when(elementCodec.decode(contextB, 21, 22, 23))
.thenReturn(new IndexableElement(elementB));
{
store.aboutToIndex(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
store.doneIndex();
}
{
store.aboutToIndex(contextB, unitElementB);
store.recordTopLevelDeclaration(elementB);
store.doneIndex();
}
// elementA, elementB
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementA, elementB]));
}
// remove "sourceA"
store.removeSource(contextA, sourceA);
{
List<Element> elements = store.getTopLevelDeclarations(anyName);
expect(elements, unorderedEquals([elementB]));
}
}
static bool anyName(String name) => true;
/**
* Asserts that the [actual] locations have all the [expected] locations and
* only them.
*/
static void assertLocations(
List<LocationImpl> actual, List<LocationImpl> expected) {
List<_LocationEqualsWrapper> actualWrappers = wrapLocations(actual);
List<_LocationEqualsWrapper> expectedWrappers = wrapLocations(expected);
expect(actualWrappers, unorderedEquals(expectedWrappers));
}
/**
* @return the new [LocationImpl] mock.
*/
static LocationImpl mockLocation(IndexableElement indexable) {
LocationImpl location = new MockLocation();
when(location.indexable).thenReturn(indexable);
when(location.offset).thenReturn(0);
when(location.length).thenReturn(0);
when(location.isQualified).thenReturn(true);
when(location.isResolved).thenReturn(true);
return location;
}
/**
* Wraps the given locations into [LocationEqualsWrapper].
*/
static List<_LocationEqualsWrapper> wrapLocations(
List<LocationImpl> locations) {
List<_LocationEqualsWrapper> wrappers = <_LocationEqualsWrapper>[];
for (LocationImpl location in locations) {
wrappers.add(new _LocationEqualsWrapper(location));
}
return wrappers;
}
}