/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.internal.index; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.dart.engine.EngineTestCase; import com.google.dart.engine.context.AnalysisContext; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.ElementLocation; import com.google.dart.engine.element.HtmlElement; import com.google.dart.engine.element.LibraryElement; import com.google.dart.engine.index.Location; import com.google.dart.engine.index.Relationship; import com.google.dart.engine.internal.context.InstrumentedAnalysisContextImpl; import com.google.dart.engine.internal.element.ElementLocationImpl; import com.google.dart.engine.internal.element.member.Member; import com.google.dart.engine.source.DirectoryBasedSourceContainer; import com.google.dart.engine.source.Source; import com.google.dart.engine.source.SourceContainer; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.List; import java.util.Set; public class MemoryIndexStoreImplTest extends EngineTestCase { /** * {@link Location} has no "equals" and "hasCode", so to compare locations by value we need to * wrap them into such object. */ private static class LocationEqualsWrapper { private final Location location; LocationEqualsWrapper(Location location) { this.location = location; } @Override public boolean equals(Object obj) { if (!(obj instanceof LocationEqualsWrapper)) { return false; } LocationEqualsWrapper other = (LocationEqualsWrapper) obj; return other.location.getOffset() == location.getOffset() && other.location.getLength() == location.getLength() && Objects.equal(other.location.getElement(), location.getElement()); } @Override public int hashCode() { return Objects.hashCode(location.getElement(), location.getOffset(), location.getLength()); } } /** * Asserts that the "actual" locations have all the "expected" locations and only them. */ private static void assertLocations(Location[] actual, Location... expected) { LocationEqualsWrapper[] actualWrappers = wrapLocations(actual); LocationEqualsWrapper[] expectedWrappers = wrapLocations(expected); assertThat(actualWrappers).containsOnly((Object[]) expectedWrappers); } /** * @return the new {@link Location} mock. */ private static Location mockLocation(Element element) { Location location = mock(Location.class); when(location.newClone()).thenReturn(location); when(location.getElement()).thenReturn(element); return location; } /** * @return the {@link SourceContainer} mock with contains given {@link Source}s. */ private static SourceContainer mockSourceContainer(Source... sources) { final Set<Source> sourceSet = ImmutableSet.<Source> builder().add(sources).build(); SourceContainer container = mock(SourceContainer.class); when(container.contains(any(Source.class))).then(new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { return sourceSet.contains(invocation.getArguments()[0]); } }); return container; } /** * Wraps the given locations into {@link LocationEqualsWrapper}. */ private static LocationEqualsWrapper[] wrapLocations(Location[] locations) { List<LocationEqualsWrapper> wrappers = Lists.newArrayList(); for (Location location : locations) { wrappers.add(new LocationEqualsWrapper(location)); } return wrappers.toArray(new LocationEqualsWrapper[wrappers.size()]); } private MemoryIndexStoreImpl store = new MemoryIndexStoreImpl(); private AnalysisContext contextA = mock(AnalysisContext.class); private AnalysisContext contextB = mock(AnalysisContext.class); private AnalysisContext contextC = mock(AnalysisContext.class); private ElementLocation elementLocationA = new ElementLocationImpl("elementLocationA"); private ElementLocation elementLocationB = new ElementLocationImpl("elementLocationB"); private ElementLocation elementLocationC = new ElementLocationImpl("elementLocationC"); private ElementLocation elementLocationD = new ElementLocationImpl("elementLocationD"); private Element elementA = mock(Element.class); private Element elementB = mock(Element.class); private Element elementC = mock(Element.class); private Element elementD = mock(Element.class); private Source librarySource = mock(Source.class); private Source sourceA = mock(Source.class); private Source sourceB = mock(Source.class); private Source sourceC = mock(Source.class); private Source sourceD = mock(Source.class); private LibraryElement libraryElement = mock(LibraryElement.class); private CompilationUnitElement libraryUnitElement = mock(CompilationUnitElement.class); private CompilationUnitElement unitElementA = mock(CompilationUnitElement.class); private CompilationUnitElement unitElementB = mock(CompilationUnitElement.class); private CompilationUnitElement unitElementC = mock(CompilationUnitElement.class); private CompilationUnitElement unitElementD = mock(CompilationUnitElement.class); private Relationship relationship = Relationship.getRelationship("test-relationship"); private Location location = mockLocation(elementC); public void test_aboutToIndex_incompleteResolution_noLibrary() throws Exception { when(unitElementA.getLibrary()).thenReturn(null); boolean mayIndex = store.aboutToIndexDart(contextA, unitElementA); assertFalse(mayIndex); } public void test_aboutToIndex_incompleteResolution_noLibraryDefiningUnit() throws Exception { when(libraryElement.getDefiningCompilationUnit()).thenReturn(null); boolean mayIndex = store.aboutToIndexDart(contextA, unitElementA); assertFalse(mayIndex); } public void test_aboutToIndex_incompleteResolution_noUnit() throws Exception { boolean mayIndex = store.aboutToIndexDart(contextA, (CompilationUnitElement) null); assertFalse(mayIndex); } public void test_aboutToIndex_removedContext() throws Exception { when(contextA.isDisposed()).thenReturn(true); store.removeContext(contextA); boolean mayIndex = store.aboutToIndexDart(contextA, unitElementA); assertFalse(mayIndex); } public void test_aboutToIndex_sharedSource_inTwoLibraries() throws Exception { Source librarySourceA = mock(Source.class); Source librarySourceB = mock(Source.class); LibraryElement libraryA = mock(LibraryElement.class); LibraryElement libraryB = mock(LibraryElement.class); CompilationUnitElement libraryAUnit = mock(CompilationUnitElement.class); CompilationUnitElement libraryBUnit = mock(CompilationUnitElement.class); when(libraryA.getDefiningCompilationUnit()).thenReturn(libraryAUnit); when(libraryB.getDefiningCompilationUnit()).thenReturn(libraryBUnit); when(libraryA.getSource()).thenReturn(librarySourceA); when(libraryB.getSource()).thenReturn(librarySourceB); when(libraryAUnit.getSource()).thenReturn(librarySourceA); when(libraryBUnit.getSource()).thenReturn(librarySourceB); when(libraryAUnit.getLibrary()).thenReturn(libraryA); when(libraryBUnit.getLibrary()).thenReturn(libraryB); // build 2 units in different libraries CompilationUnitElement unitA = mock(CompilationUnitElement.class); CompilationUnitElement unitB = mock(CompilationUnitElement.class); when(unitA.getContext()).thenReturn(contextA); when(unitB.getContext()).thenReturn(contextA); when(unitA.getSource()).thenReturn(sourceA); when(unitB.getSource()).thenReturn(sourceA); when(unitA.getLibrary()).thenReturn(libraryA); when(unitB.getLibrary()).thenReturn(libraryB); when(libraryA.getParts()).thenReturn(new CompilationUnitElement[] {unitA}); when(libraryB.getParts()).thenReturn(new CompilationUnitElement[] {unitB}); // record relationships in both A and B Location locationA = mockLocation(unitA); Location locationB = mockLocation(unitB); store.aboutToIndexDart(contextA, libraryAUnit); store.aboutToIndexDart(contextA, libraryBUnit); store.aboutToIndexDart(contextA, unitA); store.aboutToIndexDart(contextA, unitB); store.recordRelationship(elementA, relationship, locationA); store.recordRelationship(elementA, relationship, locationB); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA, locationB); } } public void test_aboutToIndex_shouldRemoveSourceKeys() throws Exception { store.recordRelationship(elementA, relationship, location); // notify that we are going to re-index "A" store.aboutToIndexDart(contextA, unitElementA); // all keys in "A" should be removed (and we don't have any other sources) assertEquals(0, store.internalGetSourceKeyCount(contextA)); } public void test_aboutToIndex_unitExcluded() throws Exception { // build library with defining unit Source librarySource = mock(Source.class); LibraryElement library = mock(LibraryElement.class); CompilationUnitElement libraryUnit = mock(CompilationUnitElement.class); when(library.getContext()).thenReturn(contextA); when(library.getDefiningCompilationUnit()).thenReturn(libraryUnit); when(library.getSource()).thenReturn(librarySource); when(libraryUnit.getContext()).thenReturn(contextA); when(libraryUnit.getSource()).thenReturn(librarySource); when(libraryUnit.getLibrary()).thenReturn(library); // build 2 library units CompilationUnitElement unitA = mock(CompilationUnitElement.class); CompilationUnitElement unitB = mock(CompilationUnitElement.class); when(unitA.getContext()).thenReturn(contextA); when(unitB.getContext()).thenReturn(contextA); when(unitA.getSource()).thenReturn(sourceA); when(unitB.getSource()).thenReturn(sourceB); when(unitA.getLibrary()).thenReturn(library); when(unitB.getLibrary()).thenReturn(library); // prepare locations Location locationA = mockLocation(unitA); Location locationB = mockLocation(unitB); // initially A and B in library when(library.getParts()).thenReturn(new CompilationUnitElement[] {unitA, unitB}); store.aboutToIndexDart(contextA, libraryUnit); store.aboutToIndexDart(contextA, unitA); store.aboutToIndexDart(contextA, unitB); store.recordRelationship(elementA, relationship, locationA); store.recordRelationship(elementA, relationship, locationB); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA, locationB); } // exclude A from library when(library.getParts()).thenReturn(new CompilationUnitElement[] {unitA}); boolean mayIndex = store.aboutToIndexDart(contextA, libraryUnit); assertTrue(mayIndex); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA); } // exclude B from library, empty now when(library.getParts()).thenReturn(new CompilationUnitElement[] {}); store.aboutToIndexDart(contextA, libraryUnit); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations); } } public void test_aboutToIndex_withHtmlElement_removedContext() throws Exception { // prepare HtmlElement HtmlElement htmlElement = mock(HtmlElement.class); when(htmlElement.getContext()).thenReturn(contextA); when(htmlElement.getSource()).thenReturn(sourceA); // mark context as removed when(contextA.isDisposed()).thenReturn(true); store.removeContext(contextA); // cannot index boolean mayIndex = store.aboutToIndexHtml(contextA, htmlElement); assertFalse(mayIndex); } public void test_aboutToIndex_withHtmlElement_shouldRemoveLocations() throws Exception { HtmlElement htmlElement = mock(HtmlElement.class); when(htmlElement.getContext()).thenReturn(contextA); when(htmlElement.getSource()).thenReturn(sourceA); location = mockLocation(htmlElement); // record location store.recordRelationship(elementA, relationship, location); assertEquals(1, store.internalGetLocationCountForContext(contextA)); // notify that we are going to re-index "A" store.aboutToIndexHtml(contextA, htmlElement); // all locations in "A" should be removed (and we don't have any other sources) assertEquals(0, store.internalGetLocationCountForContext(contextA)); } public void test_aboutToIndex_withHtmlElement_shouldRemoveSourceKeys() throws Exception { // prepare HtmlElement HtmlElement htmlElement = mock(HtmlElement.class); when(htmlElement.getContext()).thenReturn(contextA); when(htmlElement.getSource()).thenReturn(sourceA); // record with HtmlElement as a key store.recordRelationship(htmlElement, relationship, location); assertEquals(1, store.internalGetSourceKeyCount(contextA)); // notify that we are going to re-index "A" store.aboutToIndexHtml(contextA, htmlElement); // all keys in "A" should be removed (and we don't have any other sources) assertEquals(0, store.internalGetSourceKeyCount(contextA)); } public void test_clearSource_instrumented() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // clear B, 1 relation and 1 location left InstrumentedAnalysisContextImpl iContextA = mock(InstrumentedAnalysisContextImpl.class); when(iContextA.getBasis()).thenReturn(contextA); store.aboutToIndexDart(iContextA, unitElementB); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextA)); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } public void test_getRelationships_hasOne() throws Exception { store.recordRelationship(elementA, relationship, location); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, location); } public void test_getRelationships_hasTwo() throws Exception { Location locationA = mockLocation(elementA); Location locationB = mockLocation(elementB); store.recordRelationship(elementA, relationship, locationA); store.recordRelationship(elementA, relationship, locationB); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA, locationB); } public void test_getRelationships_noRelations() throws Exception { store.recordRelationship(elementA, relationship, location); Location[] locations = store.getRelationships( elementA, Relationship.getRelationship("no-such-relationship")); assertThat(locations).isEmpty(); } public void test_getRelationships_twoContexts_oneSource() throws Exception { when(unitElementB.getSource()).thenReturn(sourceB); when(unitElementC.getSource()).thenReturn(sourceB); when(elementA.getContext()).thenReturn(contextA); when(elementB.getContext()).thenReturn(contextB); Location locationA = mockLocation(elementA); Location locationB = mockLocation(elementB); store.recordRelationship(elementA, relationship, locationA); store.recordRelationship(elementB, relationship, locationB); // "elementA" { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA); } // "elementB" { Location[] locations = store.getRelationships(elementB, relationship); assertLocations(locations, locationB); } } public void test_getStatistics() throws Exception { // empty initially assertEquals("0 relationships in 0 keys in 0 sources", store.getStatistics()); // record relationship store.recordRelationship(elementA, relationship, mockLocation(elementA)); store.recordRelationship(elementA, relationship, mockLocation(elementB)); store.recordRelationship(elementB, relationship, mockLocation(elementC)); assertEquals("3 relationships in 2 keys in 2 sources", store.getStatistics()); } public void test_recordRelationship() throws Exception { // no relationships initially assertEquals(0, store.internalGetLocationCount()); // record relationship store.recordRelationship(elementA, relationship, location); assertEquals(1, store.internalGetLocationCount()); } public void test_recordRelationship_member() throws Exception { Member member = mock(Member.class); when(member.getBaseElement()).thenReturn(elementA); // no relationships initially assertEquals(0, store.internalGetLocationCount()); // record relationship store.recordRelationship(member, relationship, location); // no location for "member" { Location[] locations = store.getRelationships(member, relationship); assertLocations(locations); } // has location for "elementA" { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, location); } } public void test_recordRelationship_noElement() throws Exception { store.recordRelationship(null, relationship, location); assertEquals(0, store.internalGetLocationCount()); } public void test_recordRelationship_noElementContext() throws Exception { when(elementA.getContext()).thenReturn(null); store.recordRelationship(elementA, relationship, location); assertEquals(0, store.internalGetLocationCount()); } public void test_recordRelationship_noElementSource() throws Exception { when(elementA.getSource()).thenReturn(null); store.recordRelationship(elementA, relationship, location); assertEquals(0, store.internalGetLocationCount()); } public void test_recordRelationship_noLocation() throws Exception { store.recordRelationship(elementA, relationship, null); assertEquals(0, store.internalGetLocationCount()); } public void test_recordRelationship_noLocationContext() throws Exception { when(location.getElement().getContext()).thenReturn(null); store.recordRelationship(elementA, relationship, location); assertEquals(0, store.internalGetLocationCount()); } public void test_recordRelationship_noLocationSource() throws Exception { when(location.getElement().getSource()).thenReturn(null); store.recordRelationship(elementA, relationship, location); assertEquals(0, store.internalGetLocationCount()); } public void test_removeContext_instrumented() throws Exception { InstrumentedAnalysisContextImpl instrumentedContext = mock(InstrumentedAnalysisContextImpl.class); when(instrumentedContext.getBasis()).thenReturn(contextA); // configure B when(elementB.getContext()).thenReturn(contextA); Location locationB = mockLocation(elementB); // record: [B -> A] { store.recordRelationship(elementA, relationship, locationB); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetKeyCount()); } // remove _wrapper_ of context A InstrumentedAnalysisContextImpl iContextA = mock(InstrumentedAnalysisContextImpl.class); when(iContextA.getBasis()).thenReturn(contextA); store.removeContext(iContextA); assertEquals(0, store.internalGetLocationCount()); assertEquals(0, store.internalGetKeyCount()); } public void test_removeContext_null() throws Exception { store.removeContext(null); } public void test_removeContext_withDeclaration() throws Exception { when(elementB.getContext()).thenReturn(contextB); when(elementC.getContext()).thenReturn(contextC); // configure B and C Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); assertEquals(1, store.internalGetKeyCount()); assertEquals(0, store.internalGetLocationCountForContext(contextA)); assertEquals(1, store.internalGetLocationCountForContext(contextB)); assertEquals(1, store.internalGetLocationCountForContext(contextC)); // we get locations from all contexts Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove A, so no relations anymore // remove B, 1 relation and 1 location left store.removeContext(contextA); assertEquals(0, store.internalGetLocationCount()); assertEquals(0, store.internalGetLocationCountForContext(contextA)); assertEquals(0, store.internalGetLocationCountForContext(contextB)); assertEquals(0, store.internalGetLocationCountForContext(contextC)); { Location[] locations = store.getRelationships(elementA, relationship); assertThat(locations).isEmpty(); } } public void test_removeContext_withRelationship() throws Exception { when(elementB.getContext()).thenReturn(contextB); when(elementC.getContext()).thenReturn(contextC); // configure B and C Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.aboutToIndexDart(contextB, unitElementB); store.aboutToIndexDart(contextC, unitElementC); store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); assertEquals(0, store.internalGetLocationCountForContext(contextA)); assertEquals(1, store.internalGetLocationCountForContext(contextB)); assertEquals(1, store.internalGetLocationCountForContext(contextC)); // we get locations from all contexts Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove B, 1 relation and 1 location left store.removeContext(contextB); assertEquals(1, store.internalGetLocationCount()); assertEquals(0, store.internalGetLocationCountForContext(contextA)); assertEquals(0, store.internalGetLocationCountForContext(contextB)); assertEquals(1, store.internalGetLocationCountForContext(contextC)); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } // now remove C, empty store.removeContext(contextC); assertEquals(0, store.internalGetLocationCountForContext(contextA)); assertEquals(0, store.internalGetLocationCountForContext(contextB)); assertEquals(0, store.internalGetLocationCountForContext(contextC)); { Location[] locations = store.getRelationships(elementA, relationship); assertThat(locations).isEmpty(); } } public void test_removeSource_null() throws Exception { store.removeSource(null, null); } public void test_removeSource_withDeclaration() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove A, no relations store.removeSource(contextA, sourceA); assertEquals(0, store.internalGetLocationCount()); } public void test_removeSource_withRelationship() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove B, 1 relation and 1 location left store.removeSource(contextA, sourceB); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextA)); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } public void test_removeSource_withRelationship_instrumented() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove B, 1 relation and 1 location left InstrumentedAnalysisContextImpl iContextA = mock(InstrumentedAnalysisContextImpl.class); when(iContextA.getBasis()).thenReturn(contextA); store.removeSource(iContextA, sourceB); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextA)); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } public void test_removeSource_withRelationship_twoContexts_oneSource() throws Exception { when(elementB.getContext()).thenReturn(contextB); when(elementC.getContext()).thenReturn(contextC); when(elementC.getSource()).thenReturn(sourceB); when(unitElementC.getSource()).thenReturn(sourceB); // configure B and C Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.aboutToIndexDart(contextB, unitElementB); store.aboutToIndexDart(contextC, unitElementC); store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextB)); assertEquals(1, store.internalGetLocationCountForContext(contextC)); // we get locations from all contexts Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove "B" in B, 1 relation and 1 location left store.removeSource(contextB, sourceB); assertEquals(1, store.internalGetLocationCount()); assertEquals(0, store.internalGetLocationCountForContext(contextB)); assertEquals(1, store.internalGetLocationCountForContext(contextC)); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } // now remove "B" in C, empty store.removeSource(contextC, sourceB); assertEquals(0, store.internalGetLocationCount()); assertEquals(0, store.internalGetLocationCountForContext(contextB)); assertEquals(0, store.internalGetLocationCountForContext(contextC)); { Location[] locations = store.getRelationships(elementA, relationship); assertThat(locations).isEmpty(); } } public void test_removeSources_nullContext() throws Exception { // record { store.recordRelationship(IndexConstants.UNIVERSE, relationship, location); assertEquals(1, store.internalGetLocationCount()); } // remove "null" context, should never happen - ignored SourceContainer sourceContainer = new DirectoryBasedSourceContainer("/path/"); store.removeSources(null, sourceContainer); assertEquals(1, store.internalGetLocationCount()); } public void test_removeSources_withDeclaration() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: A, [B -> A], [C -> A] and [B -> C] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); store.recordRelationship(elementC, relationship, locationB); assertEquals(3, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove container with [A], only [B -> C] left SourceContainer containerA = mockSourceContainer(sourceA); store.removeSources(contextA, containerA); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextA)); { Location[] locations = store.getRelationships(elementC, relationship); assertLocations(locations, locationB); } } public void test_removeSources_withRelationship() throws Exception { Location locationB = mockLocation(elementB); Location locationC = mockLocation(elementC); // record: [B -> A] and [C -> A] { store.recordRelationship(elementA, relationship, locationB); store.recordRelationship(elementA, relationship, locationC); assertEquals(2, store.internalGetLocationCount()); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationB, locationC); } // remove container with [B], 1 relation and 1 location left SourceContainer containerB = mockSourceContainer(sourceB); store.removeSources(contextA, containerB); assertEquals(1, store.internalGetLocationCount()); assertEquals(1, store.internalGetLocationCountForContext(contextA)); Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationC); } public void test_tryToRecord_afterContextRemove_element() throws Exception { Location locationB = mockLocation(elementB); // remove "A" - context of "elementA" when(contextA.isDisposed()).thenReturn(true); store.removeContext(contextA); // so, this record request is ignored store.recordRelationship(elementA, relationship, locationB); assertEquals(0, store.internalGetLocationCount()); } public void test_tryToRecord_afterContextRemove_location() throws Exception { Location locationB = mockLocation(elementB); when(elementB.getContext()).thenReturn(contextB); // remove "B" - context of location when(contextB.isDisposed()).thenReturn(true); store.removeContext(contextB); // so, this record request is ignored store.recordRelationship(elementA, relationship, locationB); assertEquals(0, store.internalGetLocationCount()); } public void test_writeRead() throws Exception { when(contextA.getElement(eq(elementLocationA))).thenReturn(elementA); when(contextB.getElement(eq(elementLocationB))).thenReturn(elementB); when(elementA.getContext()).thenReturn(contextA); when(elementB.getContext()).thenReturn(contextB); // fill store Location locationA = new Location(elementA, 0, 0); Location locationB = new Location(elementB, 0, 0); store.aboutToIndexDart(contextA, unitElementA); store.aboutToIndexDart(contextB, unitElementB); store.recordRelationship(elementA, relationship, locationA); store.recordRelationship(elementB, relationship, locationB); assertEquals(2, store.internalGetKeyCount()); assertEquals(2, store.internalGetLocationCount()); assertLocations(store.getRelationships(elementA, relationship), locationA); assertLocations(store.getRelationships(elementB, relationship), locationB); // write byte[] content; { ByteArrayOutputStream baos = new ByteArrayOutputStream(); store.writeIndex(contextA, baos); content = baos.toByteArray(); } // clear store.removeContext(contextA); store.removeContext(contextB); assertEquals(0, store.internalGetKeyCount()); assertEquals(0, store.internalGetLocationCount()); // we need to re-create AnalysisContext, current instance was marked as removed { contextA = mock(AnalysisContext.class); when(contextA.getElement(eq(elementLocationA))).thenReturn(elementA); when(elementA.getContext()).thenReturn(contextA); } // read { ByteArrayInputStream bais = new ByteArrayInputStream(content); store.readIndex(contextA, bais); } // validate after read assertEquals(1, store.internalGetKeyCount()); assertEquals(1, store.internalGetLocationCount()); { Location[] locations = store.getRelationships(elementA, relationship); assertLocations(locations, locationA); } } public void test_writeRead_invalidVersion() throws Exception { // write fake content with invalid version byte[] content; { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeInt(-1); content = baos.toByteArray(); } // read try { ByteArrayInputStream bais = new ByteArrayInputStream(content); store.readIndex(contextA, bais); fail(); } catch (IOException e) { } } @Override protected void setUp() throws Exception { super.setUp(); when(contextA.toString()).thenReturn("contextA"); when(contextB.toString()).thenReturn("contextB"); when(contextC.toString()).thenReturn("contextC"); when(sourceA.toString()).thenReturn("sourceA"); when(sourceB.toString()).thenReturn("sourceB"); when(sourceC.toString()).thenReturn("sourceC"); when(sourceD.toString()).thenReturn("sourceD"); when(elementA.toString()).thenReturn("elementA"); when(elementB.toString()).thenReturn("elementB"); when(elementC.toString()).thenReturn("elementC"); when(elementD.toString()).thenReturn("elementD"); when(elementA.getContext()).thenReturn(contextA); when(elementB.getContext()).thenReturn(contextA); when(elementC.getContext()).thenReturn(contextA); when(elementD.getContext()).thenReturn(contextA); when(elementA.getLocation()).thenReturn(elementLocationA); when(elementB.getLocation()).thenReturn(elementLocationB); when(elementC.getLocation()).thenReturn(elementLocationC); when(elementD.getLocation()).thenReturn(elementLocationD); when(elementA.getEnclosingElement()).thenReturn(unitElementA); when(elementB.getEnclosingElement()).thenReturn(unitElementB); when(elementC.getEnclosingElement()).thenReturn(unitElementC); when(elementD.getEnclosingElement()).thenReturn(unitElementD); when(elementA.getSource()).thenReturn(sourceA); when(elementB.getSource()).thenReturn(sourceB); when(elementC.getSource()).thenReturn(sourceC); when(elementD.getSource()).thenReturn(sourceD); when(elementA.getLibrary()).thenReturn(libraryElement); when(elementB.getLibrary()).thenReturn(libraryElement); when(elementC.getLibrary()).thenReturn(libraryElement); when(elementD.getLibrary()).thenReturn(libraryElement); when(unitElementA.getSource()).thenReturn(sourceA); when(unitElementB.getSource()).thenReturn(sourceB); when(unitElementC.getSource()).thenReturn(sourceC); when(unitElementD.getSource()).thenReturn(sourceD); when(unitElementA.getLibrary()).thenReturn(libraryElement); when(unitElementB.getLibrary()).thenReturn(libraryElement); when(unitElementC.getLibrary()).thenReturn(libraryElement); when(unitElementD.getLibrary()).thenReturn(libraryElement); // library when(librarySource.toString()).thenReturn("libSource"); when(libraryUnitElement.getSource()).thenReturn(librarySource); when(libraryElement.getSource()).thenReturn(librarySource); when(libraryElement.getDefiningCompilationUnit()).thenReturn(libraryUnitElement); // by default index all units store.aboutToIndexDart(contextA, unitElementA); store.aboutToIndexDart(contextA, unitElementB); store.aboutToIndexDart(contextA, unitElementC); store.aboutToIndexDart(contextA, unitElementD); } }