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

Unified Diff: pkg/analysis_server/test/index/split_store_test.dart

Issue 348773003: Port SplitIndexStore to Dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes for review comments Created 6 years, 6 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analysis_server/pubspec.yaml ('k') | pkg/analysis_server/test/index/test_all.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/test/index/split_store_test.dart
diff --git a/pkg/analysis_server/test/index/split_store_test.dart b/pkg/analysis_server/test/index/split_store_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f78a6be5844b47754539554df11c900bf3359c1b
--- /dev/null
+++ b/pkg/analysis_server/test/index/split_store_test.dart
@@ -0,0 +1,1341 @@
+// 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.index.split.store;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:analysis_server/src/index/split_store.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/index.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:typed_mock/typed_mock.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+
+
+main() {
+ groupSep = ' | ';
+ group('ContextCodec', () {
+ runReflectiveTests(_ContextCodecTest);
+ });
+ group('ElementCodec', () {
+ runReflectiveTests(_ElementCodecTest);
+ });
+ group('FileNodeManager', () {
+ runReflectiveTests(_FileNodeManagerTest);
+ });
+ group('IndexNode', () {
+ runReflectiveTests(_IndexNodeTest);
+ });
+ group('IntToIntSetMap', () {
+ runReflectiveTests(_IntToIntSetMapTest);
+ });
+ group('LocationData', () {
+ runReflectiveTests(_LocationDataTest);
+ });
+ group('RelationKeyData', () {
+ runReflectiveTests(_RelationKeyDataTest);
+ });
+ group('RelationshipCodec', () {
+ runReflectiveTests(_RelationshipCodecTest);
+ });
+ group('SplitIndexStore', () {
+ runReflectiveTests(_SplitIndexStoreTest);
+ });
+ group('StringCodec', () {
+ runReflectiveTests(_StringCodecTest);
+ });
+}
+
+
+void _assertHasLocation(List<Location> locations, Element element, int offset,
+ int length) {
+ for (Location location in locations) {
+ if ((element == null || location.element == element) && location.offset ==
+ offset && location.length == length) {
+ return;
+ }
+ }
+ fail('Expected to find Location'
+ '(element=$element, offset=$offset, length=$length)');
+}
+
+
+@ReflectiveTestCase()
+class _ContextCodecTest {
+ ContextCodec codec = new ContextCodec();
+
+ void test_all() {
+ AnalysisContext contextA = new _MockAnalysisContext('contextA');
+ AnalysisContext contextB = new _MockAnalysisContext('contextB');
+ int idA = codec.encode(contextA);
+ int idB = codec.encode(contextB);
+ expect(codec.decode(idA), contextA);
+ expect(codec.decode(idB), contextB);
+ }
+}
+
+
+@ReflectiveTestCase()
+class _ElementCodecTest {
+ ElementCodec codec;
+ AnalysisContext context = new _MockAnalysisContext('context');
+ StringCodec stringCodec = new StringCodec();
+
+ void setUp() {
+ codec = new ElementCodec(stringCodec);
+ }
+
+ void test_localLocalVariable() {
+ {
+ Element element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["main", "foo@1",
+ "bar@2"]);
+ when(context.getElement(location)).thenReturn(element);
+ when(element.location).thenReturn(location);
+ int id = codec.encode(element);
+ expect(codec.decode(context, id), element);
+ }
+ {
+ Element element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["main", "foo@10",
+ "bar@20"]);
+ when(context.getElement(location)).thenReturn(element);
+ when(element.location).thenReturn(location);
+ int id = codec.encode(element);
+ expect(codec.decode(context, id), element);
+ }
+ // check strings, "foo" as a single string, no "foo@1" or "foo@10"
+ expect(stringCodec.nameToIndex, hasLength(3));
+ expect(stringCodec.nameToIndex, containsPair('main', 0));
+ expect(stringCodec.nameToIndex, containsPair('foo', 1));
+ expect(stringCodec.nameToIndex, containsPair('bar', 2));
+ }
+
+ void test_localVariable() {
+ {
+ Element element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["main",
+ "foo@42"]);
+ when(context.getElement(location)).thenReturn(element);
+ when(element.location).thenReturn(location);
+ int id = codec.encode(element);
+ expect(codec.decode(context, id), element);
+ }
+ {
+ Element element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["main",
+ "foo@4200"]);
+ when(context.getElement(location)).thenReturn(element);
+ when(element.location).thenReturn(location);
+ int id = codec.encode(element);
+ expect(codec.decode(context, id), element);
+ }
+ // check strings, "foo" as a single string, no "foo@42" or "foo@4200"
+ expect(stringCodec.nameToIndex, hasLength(2));
+ expect(stringCodec.nameToIndex, containsPair('main', 0));
+ expect(stringCodec.nameToIndex, containsPair('foo', 1));
+ }
+
+ void test_notLocal() {
+ Element element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["foo", "bar"]);
+ when(element.location).thenReturn(location);
+ when(context.getElement(location)).thenReturn(element);
+ int id = codec.encode(element);
+ expect(codec.encode(element), id);
+ expect(codec.decode(context, id), element);
+ // check strings
+ expect(stringCodec.nameToIndex, hasLength(2));
+ expect(stringCodec.nameToIndex, containsPair('foo', 0));
+ expect(stringCodec.nameToIndex, containsPair('bar', 1));
+ }
+}
+
+
+@ReflectiveTestCase()
+class _FileNodeManagerTest {
+ AnalysisContext context = new _MockAnalysisContext('context');
+ ContextCodec contextCodec = new _MockContextCodec();
+ int contextId = 13;
+ ElementCodec elementCodec = new _MockElementCodec();
+ FileManager fileManager = new _MockFileManager();
+ _MockLogger logger = new _MockLogger();
+ int nextElementId = 0;
+ FileNodeManager nodeManager;
+ RelationshipCodec relationshipCodec;
+ StringCodec stringCodec = new StringCodec();
+
+ 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.logError2(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.logError2(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
+ Element elementA = _mockElement();
+ Element elementB = _mockElement();
+ Element elementC = _mockElement();
+ Relationship relationship = Relationship.getRelationship("my-relationship");
+ // put Node
+ Future putFuture;
+ {
+ // prepare relations
+ int elementIdA = 0;
+ int elementIdB = 1;
+ int elementIdC = 2;
+ int relationshipId = relationshipCodec.encode(relationship);
+ RelationKeyData key = new RelationKeyData.forData(elementIdA,
+ relationshipId);
+ List<LocationData> locations = [new LocationData.forData(elementIdB, 1,
+ 10), new LocationData.forData(elementIdC, 2, 20)];
+ 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<Location> locations = node.getRelationships(elementA,
+ relationship);
+ expect(locations, hasLength(2));
+ _assertHasLocation(locations, elementB, 1, 10);
+ _assertHasLocation(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.logError2(anyString, anyObject)).once();
+ });
+ }
+
+ void test_removeNode() {
+ String name = "42.index";
+ nodeManager.removeNode(name);
+ verify(fileManager.delete(name)).once();
+ }
+
+ Element _mockElement() {
+ int elementId = nextElementId++;
+ Element element = new _MockElement();
+ when(elementCodec.encode(element)).thenReturn(elementId);
+ when(elementCodec.decode(context, elementId)).thenReturn(element);
+ return element;
+ }
+}
+
+
+@ReflectiveTestCase()
+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() {
+ Element elementA = _mockElement();
+ Element elementB = _mockElement();
+ Element elementC = _mockElement();
+ Relationship relationship = Relationship.getRelationship("my-relationship");
+ Location locationA = new Location(elementB, 1, 2);
+ Location locationB = new Location(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<Location> 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() {
+ Element elementA = _mockElement();
+ Element elementB = _mockElement();
+ Element elementC = _mockElement();
+ Relationship relationship = Relationship.getRelationship("my-relationship");
+ // record
+ {
+ int elementIdA = 0;
+ int elementIdB = 1;
+ int elementIdC = 2;
+ int relationshipId = relationshipCodec.encode(relationship);
+ RelationKeyData key = new RelationKeyData.forData(elementIdA,
+ relationshipId);
+ List<LocationData> locations = [new LocationData.forData(elementIdB, 1,
+ 10), new LocationData.forData(elementIdC, 2, 20)];
+ node.relations = {
+ key: locations
+ };
+ }
+ // request
+ List<Location> locations = node.getRelationships(elementA, relationship);
+ expect(locations, hasLength(2));
+ _assertHasLocation(locations, elementB, 1, 10);
+ _assertHasLocation(locations, elementC, 2, 20);
+ }
+
+ Element _mockElement() {
+ int elementId = nextElementId++;
+ Element element = new _MockElement();
+ when(elementCodec.encode(element)).thenReturn(elementId);
+ when(elementCodec.decode(context, elementId)).thenReturn(element);
+ return element;
+ }
+}
+
+
+@ReflectiveTestCase()
+class _IntToIntSetMapTest {
+ IntToIntSetMap map = new IntToIntSetMap(32, 0.75);
+
+ void test_clear() {
+ map.add(1, 10);
+ map.add(2, 20);
+ expect(map.length, 2);
+ map.clear();
+ expect(map.length, 0);
+ }
+
+ void test_get() {
+ map.add(1, 10);
+ map.add(1, 11);
+ map.add(1, 12);
+ map.add(2, 20);
+ map.add(2, 21);
+ expect(map.get(1), unorderedEquals([10, 11, 12]));
+ expect(map.get(2), unorderedEquals([20, 21]));
+ }
+
+ void test_get_no() {
+ expect(map.get(3), []);
+ }
+
+ void test_length() {
+ expect(map.length, 0);
+ map.add(1, 10);
+ expect(map.length, 1);
+ map.add(1, 11);
+ expect(map.length, 2);
+ map.add(1, 12);
+ expect(map.length, 3);
+ map.add(2, 20);
+ expect(map.length, 4);
+ map.add(2, 21);
+ expect(map.length, 5);
+ }
+}
+
+
+@ReflectiveTestCase()
+class _LocationDataTest {
+ AnalysisContext context = new _MockAnalysisContext('context');
+ ElementCodec elementCodec = new _MockElementCodec();
+ StringCodec stringCodec = new StringCodec();
+
+ void test_newForData() {
+ Element element = new _MockElement();
+ when(elementCodec.decode(context, 0)).thenReturn(element);
+ LocationData locationData = new LocationData.forData(0, 1, 2);
+ Location location = locationData.getLocation(context, elementCodec);
+ expect(location.element, element);
+ expect(location.offset, 1);
+ expect(location.length, 2);
+ }
+
+ void test_newForObject() {
+ // prepare Element
+ Element element = new _MockElement();
+ when(elementCodec.encode(element)).thenReturn(42);
+ when(elementCodec.decode(context, 42)).thenReturn(element);
+ // create
+ Location location = new Location(element, 1, 2);
+ LocationData locationData = new LocationData.forObject(elementCodec,
+ location);
+ // touch 'hashCode'
+ locationData.hashCode;
+ // ==
+ expect(locationData == new LocationData.forData(42, 1, 2), isTrue);
+ // getLocation()
+ {
+ Location newLocation = locationData.getLocation(context, elementCodec);
+ expect(location.element, element);
+ expect(location.offset, 1);
+ expect(location.length, 2);
+ }
+ // no Element - no Location
+ {
+ when(elementCodec.decode(context, 42)).thenReturn(null);
+ Location newLocation = locationData.getLocation(context, elementCodec);
+ expect(newLocation, isNull);
+ }
+ }
+}
+
+
+/**
+ * [Location] has no [==] and [hashCode], so to compare locations by value we
+ * need to wrap them into such object.
+ */
+class _LocationEqualsWrapper {
+ final Location location;
+
+ _LocationEqualsWrapper(this.location);
+
+ @override
+ int get hashCode {
+ return 31 * (31 * location.element.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.element == location.element;
+ }
+ return false;
+ }
+}
+
+
+class _MemoryNodeManager implements NodeManager {
+ ContextCodec _contextCodec = new ContextCodec();
+ ElementCodec _elementCodec;
+ int _locationCount = 0;
+ final Map<String, int> _nodeLocationCounts = new HashMap<String, int>();
+
+ final Map<String, IndexNode> _nodes = new HashMap<String, IndexNode>();
+ RelationshipCodec _relationshipCodec;
+ StringCodec _stringCodec = new StringCodec();
+
+ _MemoryNodeManager() {
+ _elementCodec = new ElementCodec(_stringCodec);
+ _relationshipCodec = new RelationshipCodec(_stringCodec);
+ }
+
+ @override
+ ContextCodec get contextCodec {
+ return _contextCodec;
+ }
+
+ @override
+ ElementCodec get elementCodec {
+ return _elementCodec;
+ }
+
+ @override
+ int get locationCount {
+ return _locationCount;
+ }
+
+ @override
+ StringCodec get stringCodec {
+ return _stringCodec;
+ }
+
+ @override
+ void clear() {
+ _nodes.clear();
+ }
+
+ int getLocationCount(String name) {
+ int locationCount = _nodeLocationCounts[name];
+ return locationCount != null ? locationCount : 0;
+ }
+
+ @override
+ Future<IndexNode> getNode(String name) {
+ return new Future.value(_nodes[name]);
+ }
+
+ bool isEmpty() {
+ for (IndexNode node in _nodes.values) {
+ Map<RelationKeyData, List<LocationData>> relations = node.relations;
+ if (!relations.isEmpty) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @override
+ IndexNode newNode(AnalysisContext context) {
+ return new IndexNode(context, elementCodec, _relationshipCodec);
+ }
+
+ @override
+ void putNode(String name, IndexNode node) {
+ // update location count
+ {
+ _locationCount -= getLocationCount(name);
+ int nodeLocationCount = node.locationCount;
+ _nodeLocationCounts[name] = nodeLocationCount;
+ _locationCount += nodeLocationCount;
+ }
+ // remember the node
+ _nodes[name] = node;
+ }
+
+ @override
+ void removeNode(String name) {
+ _nodes.remove(name);
+ }
+}
+
+
+class _MockAnalysisContext extends TypedMock implements AnalysisContext {
+ String _name;
+ _MockAnalysisContext(this._name);
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ String toString() => _name;
+}
+
+
+class _MockCompilationUnitElement extends TypedMock implements
+ CompilationUnitElement {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockContextCodec extends TypedMock implements ContextCodec {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockElement extends TypedMock implements Element {
+ String _name;
+ _MockElement([this._name = '<element>']);
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ String toString() => _name;
+}
+
+
+class _MockElementCodec extends TypedMock implements ElementCodec {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockFileManager extends TypedMock implements FileManager {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockHtmlElement extends TypedMock implements HtmlElement {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockIndexNode extends TypedMock implements IndexNode {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockInstrumentedAnalysisContextImpl extends TypedMock implements
+ InstrumentedAnalysisContextImpl {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockLibraryElement extends TypedMock implements LibraryElement {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockLocation extends TypedMock implements Location {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockLogger extends TypedMock implements Logger {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockRelationshipCodec extends TypedMock implements RelationshipCodec {
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+
+class _MockSource extends TypedMock implements Source {
+ String _name;
+ _MockSource(this._name);
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ String toString() => _name;
+}
+
+
+@ReflectiveTestCase()
+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(1, 2);
+ // equals
+ expect(keyData == this, isFalse);
+ expect(keyData == new RelationKeyData.forData(10, 20), isFalse);
+ expect(keyData == keyData, isTrue);
+ expect(keyData == new RelationKeyData.forData(1, 2), isTrue);
+ }
+
+ void test_newFromObjects() {
+ // prepare Element
+ Element element;
+ int elementId = 2;
+ {
+ element = new _MockElement();
+ ElementLocation location = new ElementLocationImpl.con3(["foo", "bar"]);
+ when(element.location).thenReturn(location);
+ when(context.getElement(location)).thenReturn(element);
+ when(elementCodec.encode(element)).thenReturn(elementId);
+ }
+ // prepare relationship
+ Relationship relationship = Relationship.getRelationship("my-relationship");
+ int relationshipId = 1;
+ when(relationshipCodec.encode(relationship)).thenReturn(relationshipId);
+ // create RelationKeyData
+ RelationKeyData keyData = new RelationKeyData.forObject(elementCodec,
+ relationshipCodec, element, relationship);
+ // touch
+ keyData.hashCode;
+ // equals
+ expect(keyData == this, isFalse);
+ expect(keyData == new RelationKeyData.forData(10, 20), isFalse);
+ expect(keyData == keyData, isTrue);
+ expect(keyData == new RelationKeyData.forData(elementId, relationshipId),
+ isTrue);
+ }
+}
+
+
+@ReflectiveTestCase()
+class _RelationshipCodecTest {
+ RelationshipCodec codec;
+ StringCodec stringCodec = new StringCodec();
+
+ void setUp() {
+ codec = new RelationshipCodec(stringCodec);
+ }
+
+ void test_all() {
+ Relationship relationship = Relationship.getRelationship("my-relationship");
+ int id = codec.encode(relationship);
+ expect(codec.decode(id), relationship);
+ }
+}
+
+
+class _SingleSourceContainer implements SourceContainer {
+ final Source _source;
+ _SingleSourceContainer(this._source);
+ @override
+ bool contains(Source source) => source == _source;
+}
+
+
+@ReflectiveTestCase()
+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');
+ ElementLocation elementLocationA = new ElementLocationImpl.con3(
+ ["/home/user/sourceA.dart", "ClassA"]);
+ ElementLocation elementLocationB = new ElementLocationImpl.con3(
+ ["/home/user/sourceB.dart", "ClassB"]);
+ ElementLocation elementLocationC = new ElementLocationImpl.con3(
+ ["/home/user/sourceC.dart", "ClassC"]);
+ ElementLocation elementLocationD = new ElementLocationImpl.con3(
+ ["/home/user/sourceD.dart", "ClassD"]);
+ HtmlElement htmlElementA = new _MockHtmlElement();
+ HtmlElement htmlElementB = new _MockHtmlElement();
+ LibraryElement libraryElement = new _MockLibraryElement();
+ Source librarySource = new _MockSource('librarySource');
+ CompilationUnitElement libraryUnitElement = new _MockCompilationUnitElement();
+ _MemoryNodeManager nodeManager = new _MemoryNodeManager();
+ Relationship relationship = Relationship.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() {
+ store = new SplitIndexStore(nodeManager);
+ when(contextA.isDisposed).thenReturn(false);
+ when(contextB.isDisposed).thenReturn(false);
+ when(contextC.isDisposed).thenReturn(false);
+ when(contextA.getElement(elementLocationA)).thenReturn(elementA);
+ when(contextA.getElement(elementLocationB)).thenReturn(elementB);
+ when(contextA.getElement(elementLocationC)).thenReturn(elementC);
+ when(contextA.getElement(elementLocationD)).thenReturn(elementD);
+ 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.location).thenReturn(elementLocationA);
+ when(elementB.location).thenReturn(elementLocationB);
+ when(elementC.location).thenReturn(elementLocationC);
+ when(elementD.location).thenReturn(elementLocationD);
+ 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);
+ when(htmlElementA.source).thenReturn(sourceA);
+ when(htmlElementB.source).thenReturn(sourceB);
+ // library
+ when(libraryUnitElement.library).thenReturn(libraryElement);
+ when(libraryUnitElement.source).thenReturn(librarySource);
+ when(libraryElement.source).thenReturn(librarySource);
+ when(libraryElement.definingCompilationUnit).thenReturn(libraryUnitElement);
+ }
+ void test_aboutToIndexDart_disposedContext() {
+ when(contextA.isDisposed).thenReturn(true);
+ expect(store.aboutToIndexDart(contextA, unitElementA), isFalse);
+ }
+ void test_aboutToIndexDart_disposedContext_wrapped() {
+ when(contextA.isDisposed).thenReturn(true);
+ InstrumentedAnalysisContextImpl instrumentedContext =
+ new _MockInstrumentedAnalysisContextImpl();
+ when(instrumentedContext.basis).thenReturn(contextA);
+ expect(store.aboutToIndexDart(instrumentedContext, unitElementA), isFalse);
+ }
+
+ void test_aboutToIndexDart_library_first() {
+ when(libraryElement.parts).thenReturn(<CompilationUnitElement>[unitElementA,
+ unitElementB]);
+ {
+ store.aboutToIndexDart(contextA, libraryUnitElement);
+ store.doneIndex();
+ }
+ {
+ List<Location> locations = store.getRelationships(elementA, relationship);
+ assertLocations(locations, []);
+ }
+ }
+
+ test_aboutToIndexDart_library_secondWithoutOneUnit() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ // "A" and "B" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ }).then((_) {
+ // apply "libraryUnitElement", only with "B"
+ when(libraryElement.parts).thenReturn([unitElementB]);
+ {
+ store.aboutToIndexDart(contextA, libraryUnitElement);
+ store.doneIndex();
+ }
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationB]);
+ });
+ });
+ }
+
+ void test_aboutToIndexDart_nullLibraryElement() {
+ when(unitElementA.library).thenReturn(null);
+ expect(store.aboutToIndexDart(contextA, unitElementA), isFalse);
+ }
+
+ void test_aboutToIndexDart_nullLibraryUnitElement() {
+ when(libraryElement.definingCompilationUnit).thenReturn(null);
+ expect(store.aboutToIndexDart(contextA, unitElementA), isFalse);
+ }
+
+ void test_aboutToIndexDart_nullUnitElement() {
+ expect(store.aboutToIndexDart(contextA, null), isFalse);
+ }
+
+ test_aboutToIndexHtml_() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexHtml(contextA, htmlElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexHtml(contextA, htmlElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ // "A" and "B" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ });
+ }
+
+ void test_aboutToIndexHtml_disposedContext() {
+ when(contextA.isDisposed).thenReturn(true);
+ expect(store.aboutToIndexHtml(contextA, htmlElementA), isFalse);
+ }
+
+ void test_clear() {
+ Location locationA = mockLocation(elementA);
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ expect(nodeManager.isEmpty(), isFalse);
+ // clear
+ store.clear();
+ expect(nodeManager.isEmpty(), isTrue);
+ }
+
+ test_getRelationships_empty() {
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> 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
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ {
+ String statistics = store.statistics;
+ expect(statistics, contains('2 locations'));
+ expect(statistics, contains('3 sources'));
+ }
+ }
+
+ void test_recordRelationship_nullElement() {
+ Location locationA = mockLocation(elementA);
+ store.recordRelationship(null, relationship, locationA);
+ store.doneIndex();
+ expect(nodeManager.isEmpty(), isTrue);
+ }
+
+ void test_recordRelationship_nullLocation() {
+ store.recordRelationship(elementA, relationship, null);
+ store.doneIndex();
+ expect(nodeManager.isEmpty(), isTrue);
+ }
+
+ test_recordRelationship_oneElement_twoNodes() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ });
+ }
+
+ test_recordRelationship_oneLocation() {
+ Location locationA = mockLocation(elementA);
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA]);
+ });
+ }
+
+ test_recordRelationship_twoLocations() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementA);
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ });
+ }
+
+ test_removeContext() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ // "A" and "B" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ }).then((_) {
+ // remove "A" context
+ store.removeContext(contextA);
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, []);
+ });
+ });
+ }
+
+ void test_removeContext_nullContext() {
+ store.removeContext(null);
+ }
+
+ test_removeSource_library() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ Location locationC = mockLocation(elementC);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementC);
+ store.recordRelationship(elementA, relationship, locationC);
+ store.doneIndex();
+ }
+ // "A", "B" and "C" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB, locationC]);
+ }).then((_) {
+ // remove "librarySource"
+ store.removeSource(contextA, librarySource);
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, []);
+ });
+ });
+ }
+
+ void test_removeSource_nullContext() {
+ store.removeSource(null, sourceA);
+ }
+
+ test_removeSource_unit() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ Location locationC = mockLocation(elementC);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementC);
+ store.recordRelationship(elementA, relationship, locationC);
+ store.doneIndex();
+ }
+ // "A", "B" and "C" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB, locationC]);
+ }).then((_) {
+ // remove "A" source
+ store.removeSource(contextA, sourceA);
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationB, locationC]);
+ });
+ });
+ }
+
+ test_removeSources_library() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ // "A" and "B" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ }).then((_) {
+ // remove "librarySource"
+ store.removeSources(contextA, new _SingleSourceContainer(librarySource));
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, []);
+ });
+ });
+ }
+
+ void test_removeSources_nullContext() {
+ store.removeSources(null, null);
+ }
+
+ test_removeSources_unit() {
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ Location locationC = mockLocation(elementC);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(elementA, relationship, locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementB);
+ store.recordRelationship(elementA, relationship, locationB);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextA, unitElementC);
+ store.recordRelationship(elementA, relationship, locationC);
+ store.doneIndex();
+ }
+ // "A", "B" and "C" locations
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationA, locationB, locationC]);
+ }).then((_) {
+ // remove "A" source
+ store.removeSources(contextA, new _SingleSourceContainer(sourceA));
+ store.removeSource(contextA, sourceA);
+ return store.getRelationshipsAsync(elementA, relationship).then(
+ (List<Location> locations) {
+ assertLocations(locations, [locationB, locationC]);
+ });
+ });
+ }
+
+ test_universe_aboutToIndex() {
+ when(contextA.getElement(elementLocationA)).thenReturn(elementA);
+ when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(UniverseElement.INSTANCE, relationship,
+ locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextB, unitElementB);
+ store.recordRelationship(UniverseElement.INSTANCE, relationship,
+ locationB);
+ store.doneIndex();
+ }
+ // get relationships
+ return store.getRelationshipsAsync(UniverseElement.INSTANCE,
+ relationship).then((List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ }).then((_) {
+ // re-index "unitElementA"
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.doneIndex();
+ return store.getRelationshipsAsync(UniverseElement.INSTANCE,
+ relationship).then((List<Location> locations) {
+ assertLocations(locations, [locationB]);
+ });
+ });
+ }
+
+ test_universe_removeContext() {
+ when(contextA.getElement(elementLocationA)).thenReturn(elementA);
+ when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ Location locationA = mockLocation(elementA);
+ Location locationB = mockLocation(elementB);
+ {
+ store.aboutToIndexDart(contextA, unitElementA);
+ store.recordRelationship(UniverseElement.INSTANCE, relationship,
+ locationA);
+ store.doneIndex();
+ }
+ {
+ store.aboutToIndexDart(contextB, unitElementB);
+ store.recordRelationship(UniverseElement.INSTANCE, relationship,
+ locationB);
+ store.doneIndex();
+ }
+ return store.getRelationshipsAsync(UniverseElement.INSTANCE,
+ relationship).then((List<Location> locations) {
+ assertLocations(locations, [locationA, locationB]);
+ }).then((_) {
+ // remove "contextA"
+ store.removeContext(contextA);
+ return store.getRelationshipsAsync(UniverseElement.INSTANCE,
+ relationship).then((List<Location> locations) {
+ assertLocations(locations, [locationB]);
+ });
+ });
+ }
+
+ /**
+ * Asserts that the "actual" locations have all the "expected" locations and only them.
+ */
+ static void assertLocations(List<Location> actual, List<Location> expected) {
+ List<_LocationEqualsWrapper> actualWrappers = wrapLocations(actual);
+ List<_LocationEqualsWrapper> expectedWrappers = wrapLocations(expected);
+ expect(actualWrappers, unorderedEquals(expectedWrappers));
+ }
+
+ /**
+ * @return the new [Location] mock.
+ */
+ static Location mockLocation(Element element) {
+ Location location = new _MockLocation();
+ when(location.element).thenReturn(element);
+ when(location.offset).thenReturn(0);
+ when(location.length).thenReturn(0);
+ return location;
+ }
+
+ /**
+ * Wraps the given locations into [LocationEqualsWrapper].
+ */
+ static List<_LocationEqualsWrapper> wrapLocations(List<Location> locations) {
+ List<_LocationEqualsWrapper> wrappers = <_LocationEqualsWrapper>[];
+ for (Location location in locations) {
+ wrappers.add(new _LocationEqualsWrapper(location));
+ }
+ return wrappers;
+ }
+}
+
+
+@ReflectiveTestCase()
+class _StringCodecTest {
+ StringCodec codec = new StringCodec();
+
+ void test_all() {
+ int idA = codec.encode('aaa');
+ int idB = codec.encode('bbb');
+ expect(codec.decode(idA), 'aaa');
+ expect(codec.decode(idB), 'bbb');
+ }
+}
« no previous file with comments | « pkg/analysis_server/pubspec.yaml ('k') | pkg/analysis_server/test/index/test_all.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698