/* Copyright (c) 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: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.api.plumbing.diff; import static com.google.common.collect.Lists.newArrayList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.locationtech.geogig.api.plumbing.diff.TreeTestSupport.createFeaturesTree; import static org.locationtech.geogig.api.plumbing.diff.TreeTestSupport.createTreesTree; import static org.locationtech.geogig.api.plumbing.diff.TreeTestSupport.featureNode; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoMoreInteractions; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.locationtech.geogig.api.Bounded; import org.locationtech.geogig.api.Bucket; import org.locationtech.geogig.api.Node; import org.locationtech.geogig.api.NodeRef; import org.locationtech.geogig.api.ObjectId; import org.locationtech.geogig.api.RevObject; import org.locationtech.geogig.api.RevObject.TYPE; import org.locationtech.geogig.api.RevTree; import org.locationtech.geogig.api.plumbing.diff.PostOrderDiffWalk.Consumer; import org.locationtech.geogig.repository.SpatialOps; import org.locationtech.geogig.storage.ObjectDatabase; import org.locationtech.geogig.storage.memory.HeapObjectDatabse; import com.vividsolutions.jts.geom.Envelope; public class PostOrderDiffWalkTest { private ObjectDatabase leftSource; private ObjectDatabase rightSource; private TestConsumer testConsumer; private static class TestConsumer implements Consumer { List</* @Nullable */Bounded> orderedLeft = new ArrayList<>(); List</* @Nullable */Bounded> orderedRight = new ArrayList<>(); @Override public void feature(Node left, Node right) { orderedLeft.add(left); orderedRight.add(right); } @Override public void tree(Node left, Node right) { orderedLeft.add(left); orderedRight.add(right); } @Override public void bucket(int bucketIndex, int bucketDepth, Bucket left, Bucket right) { orderedLeft.add(left); orderedRight.add(right); } } @Before public void beforeTest() { leftSource = new HeapObjectDatabse(); rightSource = new HeapObjectDatabse(); leftSource.open(); rightSource.open(); testConsumer = new TestConsumer(); } /** * Creates a root node for the given tree as the one {@link PostOrderDiffWalk} should use to * start the traversal */ private Node nodeFor(RevTree root) { Envelope bounds = SpatialOps.boundsOf(root); return Node.create(NodeRef.ROOT, root.getId(), ObjectId.NULL, TYPE.TREE, bounds); } @Test public void testSameRootTree() { RevTree left = createFeaturesTree(leftSource, "f", 10).build(); RevTree right = left; PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); Consumer consumer = mock(Consumer.class); visitor.walk(consumer); verifyNoMoreInteractions(consumer); } @Test public void testSameChildTree() { RevTree left = createFeaturesTree(leftSource, "f", 10).build(); RevTree right = left; PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); Consumer consumer = mock(Consumer.class); visitor.walk(consumer); verifyNoMoreInteractions(consumer); } @Test public void testSimple() { RevTree left = createFeaturesTree(leftSource, "f", 1).build(); RevTree right = createFeaturesTree(rightSource, "f", 2).build(); PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); List<? extends Bounded> expectedLeft = newArrayList(null, nodeFor(left)); List<? extends Bounded> expectedRight = newArrayList(featureNode("f", 1), nodeFor(right)); visitor.walk(testConsumer); // System.err.println(testConsumer.orderedLeft); // System.err.println(testConsumer.orderedRight); assertEquals(expectedLeft, testConsumer.orderedLeft); assertEquals(expectedRight, testConsumer.orderedRight); } @Test public void testLeafLeafTwoAdds() { // two leaf trees RevTree left = createFeaturesTree(leftSource, "f", 3).build(); RevTree right = createFeaturesTree(rightSource, "f", 5).build(); PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); List<? extends Bounded> expectedLeft = newArrayList(// null,// null,// nodeFor(left)); List<? extends Bounded> expectedRight = newArrayList(// featureNode("f", 3),// featureNode("f", 4),// nodeFor(right)); visitor.walk(testConsumer); assertEquals(expectedLeft, testConsumer.orderedLeft); assertEquals(expectedRight, testConsumer.orderedRight); } @Test public void testLeafLeafWithSubStrees() { // two leaf trees ObjectId metadataId = ObjectId.forString("fake"); RevTree left = createTreesTree(leftSource, 2, 2, metadataId).build(); RevTree right = createTreesTree(rightSource, 3, 2, metadataId).build(); PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); visitor.walk(testConsumer); List<Bounded> leftCalls = testConsumer.orderedLeft; List<Bounded> rightCalls = testConsumer.orderedRight; System.err.println(leftCalls); System.err.println(rightCalls); Node lroot = nodeFor(left); Node rroot = nodeFor(right); assertEquals(4, leftCalls.size()); assertEquals(4, rightCalls.size()); assertNull(leftCalls.get(0)); assertNull(leftCalls.get(1)); assertNull(leftCalls.get(2)); assertEquals(lroot, leftCalls.get(3)); assertEquals(rroot, rightCalls.get(3)); assertNotNull(rightCalls.get(2)); assertEquals(RevObject.TYPE.TREE, ((Node) rightCalls.get(2)).getType()); assertEquals(RevObject.TYPE.FEATURE, ((Node) rightCalls.get(1)).getType()); assertEquals(RevObject.TYPE.FEATURE, ((Node) rightCalls.get(0)).getType()); } @Test public void testBucketBucketFlat() { RevTree left = createFeaturesTree(leftSource, "f", RevTree.NORMALIZED_SIZE_LIMIT + 1) .build(); RevTree right = createFeaturesTree(rightSource, "f", RevTree.NORMALIZED_SIZE_LIMIT + 2) .build(); PostOrderDiffWalk visitor = new PostOrderDiffWalk(left, right, leftSource, rightSource); visitor.walk(testConsumer); List<Bounded> leftCalls = testConsumer.orderedLeft; List<Bounded> rightCalls = testConsumer.orderedRight; // System.err.println(leftCalls); // System.err.println(rightCalls); Node lroot = nodeFor(left); Node rroot = nodeFor(right); assertEquals(3, leftCalls.size()); assertEquals(3, rightCalls.size()); assertNull(leftCalls.get(0)); assertTrue(leftCalls.get(1) instanceof Bucket); assertEquals(lroot, leftCalls.get(2)); assertEquals(rroot, rightCalls.get(2)); assertTrue(rightCalls.get(1) instanceof Bucket); assertTrue(rightCalls.get(0) instanceof Node); assertEquals(RevObject.TYPE.FEATURE, ((Node) rightCalls.get(0)).getType()); } }