// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.set.v0_6; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Assert; import org.junit.Test; import org.openstreetmap.osmosis.core.container.v0_6.BoundContainer; import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer; import org.openstreetmap.osmosis.core.container.v0_6.NodeContainer; import org.openstreetmap.osmosis.core.domain.v0_6.Bound; import org.openstreetmap.osmosis.core.domain.v0_6.CommonEntityData; import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; import org.openstreetmap.osmosis.core.domain.v0_6.Node; import org.openstreetmap.osmosis.core.domain.v0_6.OsmUser; import org.openstreetmap.osmosis.core.merge.common.ConflictResolutionMethod; import org.openstreetmap.osmosis.core.misc.v0_6.EmptyReader; import org.openstreetmap.osmosis.core.task.v0_6.RunnableSource; import org.openstreetmap.osmosis.core.task.v0_6.Sink; import org.openstreetmap.osmosis.testutil.v0_6.RunTaskUtilities; import org.openstreetmap.osmosis.testutil.v0_6.SinkEntityInspector; /** * Tests bounding box processing in merge tasks. * * @author Igor Podolskiy */ public class MergeBoundTest { /** * A simple dummy ID generator for the helper source class. */ private static AtomicInteger idGenerator = new AtomicInteger(1000); /** * Tests the proper working of the merge task if neither * source has a declared bound. * * @throws Exception if something goes wrong */ @Test public void testNeitherHasBound() throws Exception { RunnableSource source0 = new BoundSource(new Bound(1, 2, 4, 3, "source0"), false); RunnableSource source1 = new BoundSource(new Bound(5, 6, 8, 7, "source1"), false); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); List<EntityContainer> mergedList = createList(merged.getProcessedEntities()); Assert.assertEquals(2, mergedList.size()); for (EntityContainer entityContainer : mergedList) { Assert.assertEquals(EntityType.Node, entityContainer.getEntity().getType()); } } /** * Tests whether merge will delete the declared bound if only source 0 * has a declared bound. * * @throws Exception if something goes wrong */ @Test public void testSource0HasBound() throws Exception { RunnableSource source0 = new BoundSource(new Bound(1, 2, 4, 3, "source0"), true); RunnableSource source1 = new BoundSource(new Bound(5, 6, 8, 7, "source1"), false); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); List<EntityContainer> mergedList = createList(merged.getProcessedEntities()); Assert.assertEquals(2, mergedList.size()); for (EntityContainer entityContainer : mergedList) { Assert.assertEquals(EntityType.Node, entityContainer.getEntity().getType()); } } /** * Tests whether merge will delete the declared bound if only source 1 * has a declared bound. * * @throws Exception if something goes wrong */ @Test public void testSource1HasBound() throws Exception { RunnableSource source0 = new BoundSource(new Bound(1, 2, 4, 3, "source0"), false); RunnableSource source1 = new BoundSource(new Bound(5, 6, 8, 7, "source1"), true); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); List<EntityContainer> mergedList = createList(merged.getProcessedEntities()); Assert.assertEquals(2, mergedList.size()); for (EntityContainer entityContainer : mergedList) { Assert.assertEquals(EntityType.Node, entityContainer.getEntity().getType()); } } /** * Test the proper computation of the union bound iff both sources * have bounds. * * @throws Exception if something goes wrong */ @Test public void testBothHaveBounds() throws Exception { Bound bound0 = new Bound(1, 2, 4, 3, "source1"); RunnableSource source0 = new BoundSource(bound0, true); Bound bound1 = new Bound(5, 6, 8, 7, "source2"); RunnableSource source1 = new BoundSource(bound1, true); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); List<EntityContainer> mergedList = createList(merged.getProcessedEntities()); Assert.assertEquals(3, mergedList.size()); Assert.assertEquals(EntityType.Bound, mergedList.get(0).getEntity().getType()); // Check the bound Bound bound01 = (Bound) mergedList.get(0).getEntity(); Assert.assertEquals(bound0.union(bound1), bound01); for (int i = 1; i < mergedList.size(); i++) { Assert.assertEquals(EntityType.Node, mergedList.get(i).getEntity().getType()); } } /** * Tests the proper working of the merge task if both sources are * empty. * * @throws Exception if something goes wrong */ @Test public void testBothEmpty() throws Exception { RunnableSource source0 = new EmptyReader(); RunnableSource source1 = new EmptyReader(); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); Assert.assertTrue("Expected empty result set but got some data", merged.getLastEntityContainer() == null); } /** * Tests the proper working of the merge task if exactly one source is * empty with respect to the declared bound. * * @throws Exception if something goes wrong */ @Test public void testOneSourceEmpty() throws Exception { RunnableSource source0 = new EmptyReader(); Bound bound1 = new Bound(5, 6, 8, 7, "source2"); RunnableSource source1 = new BoundSource(bound1, true); EntityMerger merger = new EntityMerger(ConflictResolutionMethod.LatestSource, 1, BoundRemovedAction.Ignore); SinkEntityInspector merged = RunTaskUtilities.run(merger, source0, source1); List<EntityContainer> mergedList = createList(merged.getProcessedEntities()); Assert.assertEquals(2, mergedList.size()); Assert.assertEquals(bound1, mergedList.get(0).getEntity()); Assert.assertEquals(EntityType.Node, mergedList.get(1).getEntity().getType()); } private static <T> List<T> createList(Iterable<T> t) { List<T> list = new ArrayList<T>(); for (T elem : t) { list.add(elem); } return list; } /** * A simple source which provides a single node in the center of a given * bounding box, and optionally, a declared bounding box. */ private static class BoundSource implements RunnableSource { private Sink sink; private Bound bound; private boolean publishBound; public BoundSource(Bound bound, boolean publishBound) { if (bound == null) { throw new IllegalArgumentException("bound must not be null"); } this.publishBound = publishBound; this.bound = bound; } @Override public void setSink(Sink sink) { this.sink = sink; } @Override public void run() { try { sink.initialize(Collections.<String, Object>emptyMap()); if (publishBound) { sink.process(new BoundContainer(bound)); } sink.process(new NodeContainer(createNode())); sink.complete(); } finally { sink.close(); } } private Node createNode() { double lon = (bound.getRight() - bound.getLeft()) / 2; double lat = (bound.getTop() - bound.getBottom()) / 2; return new Node( new CommonEntityData(idGenerator.incrementAndGet(), 1, new Date(), OsmUser.NONE, 1), lat, lon); } } }