package de.westnordost.streetcomplete.data.osm.download; import android.graphics.Rect; import android.os.Bundle; import junit.framework.TestCase; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import de.westnordost.osmapi.map.data.OsmLatLon; import de.westnordost.osmapi.map.data.OsmNode; import de.westnordost.streetcomplete.data.QuestGroup; import de.westnordost.streetcomplete.data.QuestStatus; import de.westnordost.streetcomplete.data.VisibleQuestListener; import de.westnordost.streetcomplete.data.osm.ElementGeometry; import de.westnordost.streetcomplete.data.osm.OsmElementQuestType; import de.westnordost.streetcomplete.data.osm.OsmQuest; import de.westnordost.streetcomplete.data.osm.changes.StringMapChangesBuilder; import de.westnordost.streetcomplete.data.osm.persist.ElementGeometryDao; import de.westnordost.streetcomplete.data.osm.persist.MergedElementDao; import de.westnordost.osmapi.map.data.BoundingBox; import de.westnordost.osmapi.map.data.Element; import de.westnordost.osmapi.map.data.LatLon; import de.westnordost.streetcomplete.data.osm.persist.OsmQuestDao; import de.westnordost.streetcomplete.data.tiles.DownloadedTilesDao; import de.westnordost.streetcomplete.quests.AbstractQuestAnswerFragment; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; public class OsmQuestDownloadTest extends TestCase { private ElementGeometryDao geometryDb; private MergedElementDao elementDb; private DownloadedTilesDao downloadedTilesDao; private OsmQuestDao osmQuestDao; @Override public void setUp() { geometryDb = mock(ElementGeometryDao.class); elementDb = mock(MergedElementDao.class); downloadedTilesDao = mock(DownloadedTilesDao.class); osmQuestDao = mock(OsmQuestDao.class); } public void testIgnoreBlacklistedPositionsAndInvalidGeometry() { LatLon blacklistPos = new OsmLatLon(3.0,4.0); ElementWithGeometry blacklistElement = new ElementWithGeometry(); blacklistElement.element = new OsmNode(0,0,blacklistPos,null); blacklistElement.geometry = new ElementGeometry(blacklistPos); ElementWithGeometry invalidGeometryElement = new ElementWithGeometry(); invalidGeometryElement.element = new OsmNode(0,0,new OsmLatLon(1.0,1.0),null); invalidGeometryElement.geometry = null; OsmElementQuestType questType = new ListBackedQuestType( Arrays.asList(blacklistElement, invalidGeometryElement)); setUpOsmQuestDaoMockWithNoPreviousElements(); OsmQuestDownload dl = new OsmQuestDownload(geometryDb, elementDb, osmQuestDao, downloadedTilesDao); VisibleQuestListener listener = mock(VisibleQuestListener.class); dl.setQuestListener(listener); assertEquals(0,dl.download(questType, new Rect(0,0,1,1), Collections.singleton(blacklistPos))); verify(listener, times(0)).onQuestsCreated(any(Collection.class), any(QuestGroup.class)); } public void testDeleteObsoleteQuests() { LatLon pos = new OsmLatLon(3.0,4.0); ElementWithGeometry node4 = new ElementWithGeometry(); node4.element = new OsmNode(4,0,pos,null); node4.geometry = new ElementGeometry(pos); // questType mock will only "find" the Node #4 OsmElementQuestType questType = new ListBackedQuestType(Collections.singletonList(node4)); // in the quest database mock, there are quests for node 4 and node 5 List<OsmQuest> quests = new ArrayList<>(); quests.add(new OsmQuest( 12L, questType, Element.Type.NODE, 4, QuestStatus.NEW, null, new Date(), new ElementGeometry(pos))); quests.add(new OsmQuest( 13L, questType, Element.Type.NODE, 5, QuestStatus.NEW, null, new Date(), new ElementGeometry(pos))); when(osmQuestDao.getAll( any(BoundingBox.class), any(QuestStatus.class), anyString(), any(Element.Type.class), anyLong())) .thenReturn(quests); doAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocation) throws Throwable { Collection<Long> deletedQuests = (Collection<Long>) (invocation.getArguments()[0]); assertEquals(1, deletedQuests.size()); assertEquals(13L, (long) deletedQuests.iterator().next()); return 1; } }).when(osmQuestDao).deleteAll(any(Collection.class)); OsmQuestDownload dl = new OsmQuestDownload(geometryDb, elementDb, osmQuestDao, downloadedTilesDao); VisibleQuestListener listener = mock(VisibleQuestListener.class); dl.setQuestListener(listener); // -> we expect that quest with node #5 is removed dl.download(questType, new Rect(0,0,1,1), null); verify(osmQuestDao).deleteAll(any(Collection.class)); verify(listener).onQuestsRemoved(any(Collection.class), any(QuestGroup.class)); } private void setUpOsmQuestDaoMockWithNoPreviousElements() { when(osmQuestDao.getAll( any(BoundingBox.class), any(QuestStatus.class), anyString(), any(Element.Type.class), anyLong())) .thenReturn(Collections.<OsmQuest>emptyList()); } private class ElementWithGeometry { Element element; ElementGeometry geometry; } private class ListBackedQuestType implements OsmElementQuestType { private final List<ElementWithGeometry> list; public ListBackedQuestType(List<ElementWithGeometry> list) { this.list = list; } @Override public int importance() { return 0; } @Override public AbstractQuestAnswerFragment createForm() { return null; } @Override public String getIconName() { return null; } @Override public void applyAnswerTo(Bundle answer, StringMapChangesBuilder changes) {} @Override public String getCommitMessage() { return null; } @Override public boolean download(BoundingBox bbox, MapDataWithGeometryHandler handler) { for (ElementWithGeometry e : list) { handler.handle(e.element, e.geometry); } return true; } } }