package de.westnordost.streetcomplete.data.osm.download; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.LongSparseArray; import junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import de.westnordost.streetcomplete.data.osm.ElementGeometry; import de.westnordost.osmapi.map.OsmMapDataFactory; import de.westnordost.osmapi.map.data.Element; import de.westnordost.osmapi.map.data.LatLon; import de.westnordost.osmapi.map.data.Node; import de.westnordost.osmapi.map.data.OsmLatLon; import de.westnordost.osmapi.map.data.Relation; import de.westnordost.osmapi.map.data.RelationMember; import de.westnordost.osmapi.map.data.Way; import static org.mockito.Matchers.any; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; public class OverpassMapDataParserTest extends TestCase { public void testNode() { LatLon pos = new OsmLatLon(51.7463194, 0.2428181); String xml = " <node id='5' version='1' lat='" + pos.getLatitude() + "' lon='" + pos.getLongitude() + "'/>"; Element e = parseOne(xml, null); assertTrue(e instanceof Node); Node node = (Node) e; assertEquals(pos, node.getPosition()); assertEquals(5, node.getId()); assertEquals(1, node.getVersion()); assertNull(node.getTags()); } public void testWay() { OsmLatLon[] p = new OsmLatLon[2]; p[0] = new OsmLatLon(1,2); p[1] = new OsmLatLon(3,4); String xml = "<way id='8' version='1' >\n" + " <nd ref='2' lat='" + p[0].getLatitude() + "' lon='"+p[0].getLongitude()+"' />\n" + " <nd ref='3' lat='" + p[1].getLatitude() + "' lon='"+p[1].getLongitude()+"' />\n" + "</way>"; LongSparseArray<List<LatLon>> expectedGeometry = new LongSparseArray<>(); expectedGeometry.put(8, new ArrayList<LatLon>(Arrays.asList(p))); Element e = parseOne(xml, expectedGeometry); assertTrue(e instanceof Way); Way way = (Way) e; assertEquals(8, way.getId()); assertEquals(1, way.getVersion()); assertEquals(2, way.getNodeIds().size()); assertEquals(2, (long) way.getNodeIds().get(0)); assertEquals(3, (long) way.getNodeIds().get(1)); } public void testRelation() { OsmLatLon[] p = new OsmLatLon[5]; p[0] = new OsmLatLon(1,2); p[1] = new OsmLatLon(3,4); p[2] = new OsmLatLon(5,6); p[3] = new OsmLatLon(7,8); p[4] = new OsmLatLon(9,10); String xml = "<relation id='10' version='1'>\n" + " <member type='relation' ref='4' role=''/>\n" + " <member type='way' ref='1' role='outer'>\n" + " <nd lat='" + p[0].getLatitude() + "' lon='"+p[0].getLongitude()+"'/>\n" + " <nd lat='" + p[1].getLatitude() + "' lon='"+p[1].getLongitude()+"'/>\n" + " </member>\n" + " <member type='way' ref='2' role='inner'>\n" + " <nd lat='" + p[2].getLatitude() + "' lon='"+p[2].getLongitude()+"'/>\n" + " <nd lat='" + p[3].getLatitude() + "' lon='"+p[3].getLongitude()+"'/>\n" + " </member>\n" + " <member type='node' ref='3' role='point'>\n" + " <nd lat='" + p[4].getLatitude() + "' lon='"+p[4].getLongitude()+"'/>\n" + " </member>\n" + "</relation>"; LongSparseArray<List<LatLon>> expectedGeometry = new LongSparseArray<>(); expectedGeometry.put(1, new ArrayList<LatLon>(Arrays.asList(new OsmLatLon[]{p[0], p[1]}))); expectedGeometry.put(2, new ArrayList<LatLon>(Arrays.asList(new OsmLatLon[]{p[2], p[3]}))); Element e = parseOne(xml, expectedGeometry); assertTrue(e instanceof Relation); Relation relation = (Relation) e; assertEquals(10, relation.getId()); assertEquals(1, relation.getVersion()); assertEquals(4, relation.getMembers().size()); RelationMember rm[] = new RelationMember[relation.getMembers().size()]; relation.getMembers().toArray(rm); assertEquals(4, rm[0].getRef()); assertEquals(Element.Type.RELATION, rm[0].getType()); assertEquals("", rm[0].getRole()); assertEquals(1, rm[1].getRef()); assertEquals(Element.Type.WAY, rm[1].getType()); assertEquals("outer", rm[1].getRole()); assertEquals(2, rm[2].getRef()); assertEquals(Element.Type.WAY, rm[2].getType()); assertEquals("inner", rm[2].getRole()); assertEquals(3, rm[3].getRef()); assertEquals(Element.Type.NODE, rm[3].getType()); assertEquals("point", rm[3].getRole()); assertNull(relation.getTags()); } public void testTags() { String xml = "<relation id='1' version='1' >\n" + " <tag k='a' v='b'/>" + " <tag k='c' v='d'/>" + "</relation>"; Element element = parseOne(xml, null); assertNotNull(element.getTags()); assertEquals(2, element.getTags().size()); assertEquals("b", element.getTags().get("a")); assertEquals("d", element.getTags().get("c")); } public void testParseSeveral() { String xml = "<node id='1' version='1' lat='1' lon='4'/>\n" + "<way id='1' version='1'>\n" + " <nd ref='2' lat='1' lon='3'/>\n" + " <nd ref='3' lat='2' lon='4'/>\n" + "</way>\n" + "<relation id='1' version='1'>\n" + " <member type='way' ref='2' role='inner'>\n" + " <nd lat='1' lon='3'/>\n" + " <nd lat='2' lon='4'/>\n" + " </member>\n" + "</relation>"; OverpassMapDataParser parser = new OverpassMapDataParser( new TestElementGeometryCreator(null), new OsmMapDataFactory()); MapDataWithGeometryHandler mockHandler = mock(MapDataWithGeometryHandler.class); parser.setHandler(mockHandler); parser.parse(asInputStream(xml)); verify(mockHandler, times(3)).handle(any(Element.class), isNull(ElementGeometry.class)); } private Element parseOne(String xml, LongSparseArray<List<LatLon>> expectedGeometry) { SingleElementHandler handler = new SingleElementHandler(); OverpassMapDataParser parser = new OverpassMapDataParser( new TestElementGeometryCreator(expectedGeometry), new OsmMapDataFactory()); parser.setHandler(handler); parser.parse(asInputStream(xml)); return handler.element; } private class SingleElementHandler implements MapDataWithGeometryHandler { Element element; @Override public void handle(@NonNull Element element, @Nullable ElementGeometry geometry) { this.element = element; } } /** Does not actually create the geometry but only tests if the necessary data is available when * it's methods are called */ private class TestElementGeometryCreator extends ElementGeometryCreator { private LongSparseArray<List<LatLon>> expectedGeometry; public TestElementGeometryCreator(LongSparseArray<List<LatLon>> expectedGeometry) { this.expectedGeometry = expectedGeometry; } @Override public ElementGeometry create(Node node) { return null; } @Override public ElementGeometry create(Way way) { if(expectedGeometry == null) return null; assertEquals(expectedGeometry.get(way.getId()), data.getNodePositions(way.getId())); return null; } @Override public ElementGeometry create(Relation relation) { if(expectedGeometry == null) return null; for(RelationMember rm : relation.getMembers()) { if(rm.getType() == Element.Type.WAY) { assertEquals(expectedGeometry.get(rm.getRef()), data.getNodePositions(rm.getRef())); } } return null; } } private static InputStream asInputStream(String str) { try { return new ByteArrayInputStream(str.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) {} return null; } }