/* Copyright (c) 2013-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Victor Olaya (Boundless) - initial implementation
*/
package org.locationtech.geogig.osm.internal;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.RevFeature;
import org.locationtech.geogig.api.RevFeatureType;
import org.locationtech.geogig.api.plumbing.LsTreeOp;
import org.locationtech.geogig.api.plumbing.ResolveFeatureType;
import org.locationtech.geogig.api.plumbing.RevObjectParse;
import org.locationtech.geogig.api.porcelain.AddOp;
import org.locationtech.geogig.api.porcelain.CommitOp;
import org.locationtech.geogig.osm.internal.MappingRule.DefaultField;
import org.locationtech.geogig.osm.internal.log.ResolveOSMMappingLogFolder;
import org.locationtech.geogig.repository.WorkingTree;
import org.locationtech.geogig.storage.FieldType;
import org.locationtech.geogig.test.integration.RepositoryTestCase;
import org.opengis.feature.type.PropertyDescriptor;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class OSMMapOpTest extends RepositoryTestCase {
@Rule
public ExpectedException exception = ExpectedException.none();
@Override
protected void setUpInternal() throws Exception {
repo.configDatabase().put("user.name", "groldan");
repo.configDatabase().put("user.email", "groldan@boundlessgeo.com");
}
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void testMappingWays() throws Exception {
// import and check that we have both ways and nodes
String filename = OSMImportOp.class.getResource("ways.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
filter.put("oneway", Lists.newArrayList("yes"));
fields.put("geom", new AttributeDefinition("geom", FieldType.LINESTRING));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("onewaystreets", filter, filterExclude, fields,
null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:onewaystreets/31045880").call(RevFeature.class);
assertTrue(revFeature.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
assertEquals(4, values.size());
String wkt = "LINESTRING (7.1923367 50.7395887, 7.1923127 50.7396946, 7.1923444 50.7397419, 7.1924199 50.7397781)";
assertEquals(wkt, values.get(2).get().toString());
assertEquals("yes", values.get(1).get());
// Check that the corresponding log files have been added
File osmMapFolder = geogig.command(ResolveOSMMappingLogFolder.class).call();
file = new File(osmMapFolder, "onewaystreets");
assertTrue(file.exists());
file = new File(osmMapFolder, geogig.getRepository().workingTree().getTree().getId()
.toString());
assertTrue(file.exists());
}
@Test
public void testMappingDefaultFields() throws Exception {
// import and check that we have both ways and nodes
String filename = OSMImportOp.class.getResource("ways.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
filter.put("oneway", Lists.newArrayList("yes"));
fields.put("geom", new AttributeDefinition("geom", FieldType.LINESTRING));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
ArrayList<DefaultField> defaultFields = Lists.newArrayList();
defaultFields.add(DefaultField.timestamp);
defaultFields.add(DefaultField.visible);
MappingRule mappingRule = new MappingRule("onewaystreets", filter, null, fields,
defaultFields);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:onewaystreets/31045880").call(RevFeature.class);
assertTrue(revFeature.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
assertEquals(6, values.size());
String wkt = "LINESTRING (7.1923367 50.7395887, 7.1923127 50.7396946, 7.1923444 50.7397419, 7.1924199 50.7397781)";
assertEquals(wkt, values.get(4).get().toString());
assertEquals("yes", values.get(3).get());
assertEquals(true, values.get(2).get());
assertEquals(1318750940000L, values.get(1).get());
Optional<RevFeatureType> revFeatureType = geogig.command(ResolveFeatureType.class)
.setRefSpec("HEAD:onewaystreets/31045880").call();
assertTrue(revFeatureType.isPresent());
ImmutableList<PropertyDescriptor> descriptors = revFeatureType.get().sortedDescriptors();
assertEquals("timestamp", descriptors.get(1).getName().toString());
assertEquals("visible", descriptors.get(2).getName().toString());
}
@Test
public void testMappingOnlyClosedPolygons() throws Exception {
// import and check that we have both ways and nodes
String filename = OSMImportOp.class.getResource("ways_restriction.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
filter.put("geom", Lists.newArrayList("closed"));
fields.put("geom", new AttributeDefinition("geom", FieldType.POLYGON));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("polygons", filter, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:polygons/31045880").call(RevFeature.class);
assertTrue(revFeature.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
assertEquals(4, values.size());
String wkt = "POLYGON ((7.1923367 50.7395887, 7.1923127 50.7396946, 7.1923444 50.7397419, 7.1924199 50.7397781, 7.1923367 50.7395887))";
assertEquals(wkt, values.get(2).get().toString());
assertEquals("yes", values.get(1).get());
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:polygons/24777894")
.call(RevFeature.class);
assertFalse(revFeature.isPresent());
}
@Test
public void testExcludePoligonsWithLessThan3Points() throws Exception {
// import and check that we have both ways and nodes
String filename = OSMImportOp.class.getResource("ways_restriction.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
fields.put("geom", new AttributeDefinition("geom", FieldType.POLYGON));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("polygons", filter, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:polygons/31045880").call(RevFeature.class);
assertTrue(revFeature.isPresent());
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:polygons/24777894")
.call(RevFeature.class);
assertTrue(revFeature.isPresent());
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:polygons/51502277")
.call(RevFeature.class);
assertFalse(revFeature.isPresent());
}
@Test
public void testMappingOnlyOpenLines() throws Exception {
// import and check that we have both ways and nodes
String filename = OSMImportOp.class.getResource("ways_restriction.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
filter.put("geom", Lists.newArrayList("open"));
fields.put("geom", new AttributeDefinition("geom", FieldType.LINESTRING));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("nonclosed", filter, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:nonclosed/31045880").call(RevFeature.class);
assertFalse(revFeature.isPresent());
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:nonclosed/24777894")
.call(RevFeature.class);
assertTrue(revFeature.isPresent());
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:nonclosed/51502277")
.call(RevFeature.class);
assertTrue(revFeature.isPresent());
}
@Test
public void testMappingNodes() throws Exception {
// import and check that we have nodes
String filename = OSMImportOp.class.getResource("nodes.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> mappings = Maps.newHashMap();
mappings.put("highway", Lists.newArrayList("bus_stop"));
fields.put("geom", new AttributeDefinition("geom", FieldType.POINT));
fields.put("name", new AttributeDefinition("name", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("busstops", mappings, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:busstops/507464799").call(RevFeature.class);
assertTrue(revFeature.isPresent());
Optional<RevFeatureType> featureType = geogig.command(ResolveFeatureType.class)
.setRefSpec("HEAD:busstops/507464799").call();
assertTrue(featureType.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
assertEquals(3, values.size());
String wkt = "POINT (7.1959361 50.739397)";
assertEquals(wkt, values.get(2).get().toString());
assertEquals(507464799l, values.get(0).get());
// Check that the corresponding log files have been added
File osmMapFolder = geogig.command(ResolveOSMMappingLogFolder.class).call();
file = new File(osmMapFolder, "busstops");
assertTrue(file.exists());
file = new File(osmMapFolder, geogig.getRepository().workingTree().getTree().getId()
.toString());
assertTrue(file.exists());
}
@Test
public void testMappingWithExclusion() throws Exception {
// import and check that we have nodes
String filename = OSMImportOp.class.getResource("nodes.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filter = Maps.newHashMap();
Map<String, List<String>> filterExclude = Maps.newHashMap();
filter.put("highway", Lists.newArrayList("bus_stop"));
filterExclude.put("public_transport", Lists.newArrayList("stop_position"));
fields.put("geom", new AttributeDefinition("geom", FieldType.POINT));
fields.put("name", new AttributeDefinition("name", FieldType.STRING));
fields.put("name", new AttributeDefinition("name", FieldType.STRING));
MappingRule mappingRule = new MappingRule("busstops", filter, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:busstops/507464799").call(RevFeature.class);
assertTrue(revFeature.isPresent());
Optional<RevFeatureType> featureType = geogig.command(ResolveFeatureType.class)
.setRefSpec("HEAD:busstops/507464799").call();
assertTrue(featureType.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
assertEquals(3, values.size());
String wkt = "POINT (7.1959361 50.739397)";
assertEquals(wkt, values.get(2).get().toString());
assertEquals(507464799l, values.get(0).get());
// Check that the excluded feature is missing
revFeature = geogig.command(RevObjectParse.class).setRefSpec("HEAD:busstops/507464865")
.call(RevFeature.class);
assertFalse(revFeature.isPresent());
}
@Test
public void testMappingNodesWithAlias() throws Exception {
// import and check that we have nodes
String filename = OSMImportOp.class.getResource("nodes.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define mapping
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> mappings = Maps.newHashMap();
mappings.put("highway", Lists.newArrayList("bus_stop"));
fields.put("geom", new AttributeDefinition("the_geometry", FieldType.POINT));
fields.put("name", new AttributeDefinition("the_name", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("busstops", mappings, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
// Check that mapping was correctly performed
Optional<RevFeature> revFeature = geogig.command(RevObjectParse.class)
.setRefSpec("HEAD:busstops/507464799").call(RevFeature.class);
assertTrue(revFeature.isPresent());
Optional<RevFeatureType> featureType = geogig.command(ResolveFeatureType.class)
.setRefSpec("HEAD:busstops/507464799").call();
assertTrue(featureType.isPresent());
ImmutableList<Optional<Object>> values = revFeature.get().getValues();
ImmutableList<PropertyDescriptor> descriptors = featureType.get().sortedDescriptors();
assertEquals("the_name", descriptors.get(1).getName().getLocalPart());
assertEquals("Gielgen", values.get(1).get());
assertEquals("the_geometry", descriptors.get(2).getName().getLocalPart());
}
@Test
public void testMappingwithNoGeometry() throws Exception {
// Test that an exception is thrown when the mapping does not contain a geometry field
String filename = OSMImportOp.class.getResource("ways.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
unstaged = workTree.countUnstaged("node").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
// Define a wrong mapping without geometry
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filters = Maps.newHashMap();
filters.put("oneway", Lists.newArrayList("yes"));
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("onewaystreets", filters, filterExclude, fields,
null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
// Try to create a mapping
try {
geogig.command(OSMMapOp.class).setMapping(mapping).call();
fail();
} catch (NullPointerException e) {
assertTrue(e.getMessage().startsWith(
"The mapping rule does not define a geometry field"));
}
}
@Test
public void testMappingWithNoFilter() throws Exception {
// Test that if no filter is specified in a mapping rule, all entities pass the filter
String filename = OSMImportOp.class.getResource("ways.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filters = Maps.newHashMap();
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
fields.put("geom", new AttributeDefinition("geom", FieldType.LINESTRING));
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("allways", filters, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
Iterator<NodeRef> allways = geogig.command(LsTreeOp.class).setReference("HEAD:allways")
.call();
assertTrue(allways.hasNext());
Iterator<NodeRef> ways = geogig.command(LsTreeOp.class).setReference("HEAD:allways").call();
ArrayList<NodeRef> listWays = Lists.newArrayList(ways);
ArrayList<NodeRef> listAllways = Lists.newArrayList(allways);
assertEquals(listWays.size(), listAllways.size());
}
@Test
public void testMappingWithEmptyTagValueList() throws Exception {
// Test that when no tags are specified, all entities pass the filter
String filename = OSMImportOp.class.getResource("ways.xml").getFile();
File file = new File(filename);
geogig.command(OSMImportOp.class).setDataSource(file.getAbsolutePath()).call();
WorkingTree workTree = geogig.getRepository().workingTree();
long unstaged = workTree.countUnstaged("way").count();
assertTrue(unstaged > 0);
geogig.command(AddOp.class).call();
geogig.command(CommitOp.class).setMessage("msg").call();
Map<String, AttributeDefinition> fields = Maps.newHashMap();
Map<String, List<String>> filters = Maps.newHashMap();
fields.put("lit", new AttributeDefinition("lit", FieldType.STRING));
fields.put("geom", new AttributeDefinition("geom", FieldType.POINT));
filters.put("highway", new ArrayList<String>());
Map<String, List<String>> filterExclude = Maps.newHashMap();
MappingRule mappingRule = new MappingRule("mapped", filters, filterExclude, fields, null);
List<MappingRule> mappingRules = Lists.newArrayList();
mappingRules.add(mappingRule);
Mapping mapping = new Mapping(mappingRules);
geogig.command(OSMMapOp.class).setMapping(mapping).call();
Iterator<NodeRef> iter = geogig.command(LsTreeOp.class).setReference("HEAD:mapped").call();
ArrayList<NodeRef> list = Lists.newArrayList(iter);
assertEquals(4, list.size());
}
}