/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tinkerpop.gremlin.process.traversal; import org.apache.tinkerpop.gremlin.process.traversal.step.util.ImmutablePath; import org.apache.tinkerpop.gremlin.process.traversal.step.util.MutablePath; import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedPath; import org.apache.tinkerpop.gremlin.structure.util.reference.ReferencePath; import org.junit.Test; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class PathTest { private final static List<Supplier<Path>> PATH_SUPPLIERS = Arrays.asList(MutablePath::make, ImmutablePath::make, DetachedPath::make, ReferencePath::make); @Test public void shouldHaveStandardSemanticsImplementedCorrectly() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); assertTrue(path.isSimple()); assertEquals(0, path.size()); path = path.extend(1, Collections.singleton("a")); path = path.extend(2, Collections.singleton("b")); path = path.extend(3, Collections.singleton("c")); assertEquals(3, path.size()); assertEquals(Integer.valueOf(1), path.get("a")); assertEquals(Integer.valueOf(2), path.get("b")); assertEquals(Integer.valueOf(3), path.get("c")); path = path.extend(Collections.singleton("d")); assertEquals(3, path.size()); assertEquals(Integer.valueOf(1), path.get("a")); assertEquals(Integer.valueOf(2), path.get("b")); assertEquals(Integer.valueOf(3), path.get("c")); assertEquals(Integer.valueOf(3), path.get("d")); assertTrue(path.hasLabel("a")); assertTrue(path.hasLabel("b")); assertTrue(path.hasLabel("c")); assertTrue(path.hasLabel("d")); assertFalse(path.hasLabel("e")); assertTrue(path.isSimple()); path = path.extend(3, Collections.singleton("e")); assertFalse(path.isSimple()); assertTrue(path.hasLabel("e")); assertEquals(4, path.size()); assertEquals(Integer.valueOf(1), path.get(0)); assertEquals(Integer.valueOf(2), path.get(1)); assertEquals(Integer.valueOf(3), path.get(2)); assertEquals(Integer.valueOf(3), path.get(3)); Path retractedPath = path.retract(Collections.singleton("f")).clone(); assertFalse(path.hasLabel("f")); assertEquals(4, path.size()); assertEquals(retractedPath, path); path = path.retract(Collections.singleton("b")); assertFalse(path.hasLabel("b")); assertEquals(3, path.size()); assertEquals(retractedPath.retract(Collections.singleton("b")), path); path = path.retract(Collections.singleton("a")); assertEquals(2, path.size()); assertFalse(path.hasLabel("a")); assertTrue(path.hasLabel("d")); path = path.retract(new HashSet<>(Arrays.asList("c", "d"))); assertFalse(path.hasLabel("c")); assertFalse(path.hasLabel("d")); assertTrue(path.hasLabel("e")); assertEquals(1, path.size()); path = path.retract(Collections.singleton("e")); assertFalse(path.hasLabel("c")); assertFalse(path.hasLabel("d")); assertFalse(path.hasLabel("e")); assertNotEquals(retractedPath, path); assertEquals(0, path.size()); }); } @Test public void shouldHandleMultiLabelPaths() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", Collections.singleton("a")); path = path.extend("stephen", Collections.singleton("b")); path = path.extend("matthias", Collections.singleton("a")); assertEquals(3, path.size()); assertEquals(3, path.objects().size()); assertEquals(3, path.labels().size()); assertEquals(2, new HashSet<>(path.labels()).size()); assertTrue(path.get("a") instanceof List); assertTrue(path.get("b") instanceof String); assertEquals(2, path.<List<String>>get("a").size()); assertTrue(path.<List<String>>get("a").contains("marko")); assertTrue(path.<List<String>>get("a").contains("matthias")); }); } @Test public void shouldExcludeUnlabeledLabelsFromPath() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", Collections.singleton("a")); path = path.extend("stephen", Collections.singleton("b")); path = path.extend("matthias", new LinkedHashSet<>(Arrays.asList("c", "d"))); assertEquals(3, path.size()); assertEquals(3, path.objects().size()); assertEquals(3, path.labels().size()); assertEquals(1, path.labels().get(0).size()); assertEquals(1, path.labels().get(1).size()); assertEquals("b", path.labels().get(1).iterator().next()); assertEquals(2, path.labels().get(2).size()); assertTrue(path.labels().get(2).contains("c")); assertTrue(path.labels().get(2).contains("d")); }); } @Test public void shouldHaveOrderedPathLabels() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", new LinkedHashSet<>(Arrays.asList("a", "b"))); path = path.extend("stephen", new LinkedHashSet<>(Arrays.asList("c", "a"))); path = path.extend("matthias", new LinkedHashSet<>(Arrays.asList("a", "b"))); assertEquals(3, path.size()); assertEquals(3, path.objects().size()); assertEquals(3, path.labels().size()); assertEquals(2, path.labels().get(0).size()); assertEquals(2, path.labels().get(1).size()); assertEquals(2, path.labels().get(2).size()); /// Iterator<String> labels = path.labels().get(0).iterator(); assertEquals("a", labels.next()); assertEquals("b", labels.next()); assertFalse(labels.hasNext()); labels = path.labels().get(1).iterator(); assertEquals("c", labels.next()); assertEquals("a", labels.next()); assertFalse(labels.hasNext()); labels = path.labels().get(2).iterator(); assertEquals("a", labels.next()); assertEquals("b", labels.next()); assertFalse(labels.hasNext()); /// List<String> names = path.get("a"); assertEquals("marko", names.get(0)); assertEquals("stephen", names.get(1)); assertEquals("matthias", names.get(2)); names = path.get("b"); assertEquals("marko", names.get(0)); assertEquals("matthias", names.get(1)); assertEquals("stephen", path.get("c")); }); } @Test public void shouldSelectSingleCorrectly() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", new LinkedHashSet<String>(Arrays.asList("a", "b"))); path = path.extend("stephen", new LinkedHashSet<>(Arrays.asList("a", "c"))); path = path.extend("matthias", new LinkedHashSet<>(Arrays.asList("c", "d"))); assertEquals(3, path.size()); assertEquals("marko", path.get(Pop.first, "a")); assertEquals("marko", path.get(Pop.first, "b")); assertEquals("stephen", path.get(Pop.first, "c")); assertEquals("matthias", path.get(Pop.first, "d")); /// assertEquals("marko", path.get(Pop.last, "b")); assertEquals("stephen", path.get(Pop.last, "a")); assertEquals("matthias", path.get(Pop.last, "c")); assertEquals("matthias", path.get(Pop.last, "d")); }); } @Test public void shouldSelectListCorrectly() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", new LinkedHashSet<>(Arrays.asList("a", "b"))); path = path.extend("stephen", new LinkedHashSet<>(Arrays.asList("a", "c"))); path = path.extend("matthias", new LinkedHashSet<>(Arrays.asList("c", "d"))); assertEquals(3, path.size()); assertEquals(2, path.<List>get(Pop.all, "a").size()); assertEquals("marko", path.<List>get(Pop.all, "a").get(0)); assertEquals("stephen", path.<List>get(Pop.all, "a").get(1)); assertEquals(1, path.<List>get(Pop.all, "b").size()); assertEquals("marko", path.<List>get(Pop.all, "b").get(0)); assertEquals(2, path.<List>get(Pop.all, "c").size()); assertEquals("stephen", path.<List>get(Pop.all, "c").get(0)); assertEquals("matthias", path.<List>get(Pop.all, "c").get(1)); assertEquals(1, path.<List>get(Pop.all, "d").size()); assertEquals("matthias", path.<List>get(Pop.all, "d").get(0)); /// assertEquals(0, path.<List>get(Pop.all, "noExist").size()); }); } @Test public void shouldHaveEquality() { PATH_SUPPLIERS.forEach(supplier -> { Path pathA1 = supplier.get(); Path pathA2 = supplier.get(); Path pathB1 = supplier.get(); Path pathB2 = supplier.get(); assertEquals(pathA1, pathA2); assertEquals(pathA1.hashCode(), pathA2.hashCode()); assertEquals(pathA2, pathB1); assertEquals(pathA2.hashCode(), pathB1.hashCode()); assertEquals(pathB1, pathB2); assertEquals(pathB1.hashCode(), pathB2.hashCode()); /// pathA1 = pathA1.extend("marko", Collections.singleton("a")); pathA2 = pathA2.extend("marko", Collections.singleton("a")); pathB1 = pathB1.extend("marko", Collections.singleton("b")); pathB2 = pathB2.extend("marko", Collections.singleton("b")); assertEquals(pathA1, pathA2); assertEquals(pathA1.hashCode(), pathA2.hashCode()); assertNotEquals(pathA2, pathB1); assertEquals(pathB1, pathB2); assertEquals(pathB1.hashCode(), pathB2.hashCode()); /// pathA1 = pathA1.extend("daniel", new LinkedHashSet<>(Arrays.asList("aa", "aaa"))); pathA2 = pathA2.extend("daniel", new LinkedHashSet<>(Arrays.asList("aa", "aaa"))); pathB1 = pathB1.extend("stephen", new LinkedHashSet<>(Arrays.asList("bb", "bbb"))); pathB2 = pathB2.extend("stephen", Collections.singleton("bb")); assertEquals(pathA1, pathA2); assertEquals(pathA1.hashCode(), pathA2.hashCode()); assertNotEquals(pathA2, pathB1); assertNotEquals(pathB1, pathB2); /// pathA1 = pathA1.extend("matthias", new LinkedHashSet<>(Arrays.asList("aaaa", "aaaaa"))); pathA2 = pathA2.extend("bob", new LinkedHashSet<>(Arrays.asList("aaaa", "aaaaa"))); pathB1 = pathB1.extend("byn", Collections.singleton("bbbb")); pathB2 = pathB2.extend("bryn", Collections.singleton("bbbb")); assertNotEquals(pathA1, pathA2); assertNotEquals(pathA2, pathB1); assertNotEquals(pathB1, pathB2); }); } @Test public void shouldHavePopEquality() { PATH_SUPPLIERS.forEach(supplier -> { Path pathA1 = supplier.get(); Path pathA2 = supplier.get(); Path pathB1 = supplier.get(); Path pathB2 = supplier.get(); assertTrue(pathA1.popEquals(Pop.all, pathA2)); assertTrue(pathA2.popEquals(Pop.all, pathB1)); assertTrue(pathB1.popEquals(Pop.all, pathB2)); assertTrue(pathA1.popEquals(Pop.first, pathA2)); assertTrue(pathA2.popEquals(Pop.first, pathB1)); assertTrue(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathA1.popEquals(Pop.last, pathA2)); assertTrue(pathA2.popEquals(Pop.last, pathB1)); assertTrue(pathB1.popEquals(Pop.last, pathB2)); /// pathA1 = pathA1.extend("marko", Collections.singleton("a")); pathA2 = pathA2.extend("marko", Collections.singleton("a")); pathB1 = pathB1.extend("matthias", Collections.singleton("a")); pathB2 = pathB2.extend("matthias", Collections.singleton("a")); assertTrue(pathA1.popEquals(Pop.all, pathA2)); assertFalse(pathA2.popEquals(Pop.all, pathB1)); assertTrue(pathB1.popEquals(Pop.all, pathB2)); assertTrue(pathA1.popEquals(Pop.first, pathA2)); assertFalse(pathA2.popEquals(Pop.first, pathB1)); assertTrue(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathA1.popEquals(Pop.last, pathA2)); assertFalse(pathA2.popEquals(Pop.last, pathB1)); assertTrue(pathB1.popEquals(Pop.last, pathB2)); /// pathA1 = pathA1.extend("matthias", Collections.singleton("a")); pathA2 = pathA2.extend("matthias", Collections.singleton("a")); pathB1 = pathB1.extend("marko", Collections.singleton("a")); pathB2 = pathB2.extend("marko", Collections.singleton("a")); assertTrue(pathA1.popEquals(Pop.all, pathA2)); assertFalse(pathA2.popEquals(Pop.all, pathB1)); assertTrue(pathB1.popEquals(Pop.all, pathB2)); assertTrue(pathA1.popEquals(Pop.first, pathA2)); assertFalse(pathA2.popEquals(Pop.first, pathB1)); assertTrue(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathA1.popEquals(Pop.last, pathA2)); assertFalse(pathA2.popEquals(Pop.last, pathB1)); assertTrue(pathB1.popEquals(Pop.last, pathB2)); /// pathA1 = pathA1.extend("bob", Collections.singleton("a")); pathA2 = pathA2.extend("bob", Collections.singleton("a")); pathB1 = pathB1.extend("bob", Collections.singleton("a")); pathB2 = pathB2.extend("bob", Collections.singleton("a")); assertTrue(pathA1.popEquals(Pop.all, pathA2)); assertFalse(pathA2.popEquals(Pop.all, pathB1)); assertTrue(pathB1.popEquals(Pop.all, pathB2)); assertTrue(pathA1.popEquals(Pop.first, pathA2)); assertFalse(pathA2.popEquals(Pop.first, pathB1)); assertTrue(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathA1.popEquals(Pop.last, pathA2)); assertTrue(pathA2.popEquals(Pop.last, pathB1)); assertTrue(pathB1.popEquals(Pop.last, pathB2)); /// pathA1 = pathA1.extend("stephen", Collections.singleton("b")); pathA2 = pathA2.extend("stephen", Collections.singleton("b")); pathB1 = pathB1.extend("stephen", Collections.singleton("b")); pathB2 = pathB2.extend("stephen", Collections.singleton("b")); assertTrue(pathA1.popEquals(Pop.all, pathA2)); assertFalse(pathA2.popEquals(Pop.all, pathB1)); assertTrue(pathB1.popEquals(Pop.all, pathB2)); assertTrue(pathA1.popEquals(Pop.first, pathA2)); assertFalse(pathA2.popEquals(Pop.first, pathB1)); assertTrue(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathA1.popEquals(Pop.last, pathA2)); assertTrue(pathA2.popEquals(Pop.last, pathB1)); assertTrue(pathB1.popEquals(Pop.last, pathB2)); /// pathA1 = pathA1.extend("stephen", Collections.singleton("c")); pathA2 = pathA2.extend("stephen", Collections.singleton("d")); pathB1 = pathB1.extend("marko", Collections.singleton("e")); pathB2 = pathB2.extend("stephen", Collections.singleton("f")); assertTrue(pathA1.popEquals(Pop.all, pathA1)); assertFalse(pathA1.popEquals(Pop.all, pathA2)); assertFalse(pathA2.popEquals(Pop.all, pathB1)); assertFalse(pathB1.popEquals(Pop.all, pathB2)); assertFalse(pathA1.popEquals(Pop.first, pathA2)); assertFalse(pathA2.popEquals(Pop.first, pathB1)); assertFalse(pathB1.popEquals(Pop.first, pathB2)); assertTrue(pathB1.popEquals(Pop.first, pathB1)); assertFalse(pathA1.popEquals(Pop.last, pathA2)); assertFalse(pathA2.popEquals(Pop.last, pathB1)); assertFalse(pathB1.popEquals(Pop.last, pathB2)); assertTrue(pathB2.popEquals(Pop.last, pathB2)); }); } @Test public void shouldHaveCrossTypeEquality() { List<Path> paths = PATH_SUPPLIERS.stream() .map(Supplier::get) .map(path -> path.extend("marko", new LinkedHashSet<>(Arrays.asList("a", "aa")))) .map(path -> path.extend("daniel", Collections.singleton("b"))) .collect(Collectors.toList()); for (final Path pathA : paths) { for (final Path pathB : paths) { assertEquals(pathA, pathB); assertEquals(pathA.hashCode(), pathB.hashCode()); } } } @Test public void shouldHaveSubPathSupport() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", Collections.singleton("a")); path = path.extend("stephen", Collections.singleton("b")); path = path.extend("matthias", new HashSet<>(Arrays.asList("c", "x"))); path = path.extend("bob", Collections.singleton("d")); assertEquals(4, path.size()); assertEquals(4, path.objects().size()); assertEquals(4, path.labels().size()); /// Path subPath = path.subPath("b", "c"); assertEquals(2, subPath.size()); assertEquals(2, subPath.objects().size()); assertEquals(2, subPath.labels().size()); assertEquals("stephen", subPath.objects().get(0)); assertEquals("matthias", subPath.objects().get(1)); assertTrue(subPath.labels().get(0).contains("b")); assertEquals(1, subPath.labels().get(0).size()); assertTrue(subPath.labels().get(1).contains("c")); assertTrue(subPath.labels().get(1).contains("x")); assertEquals(2, subPath.labels().get(1).size()); /// subPath = path.subPath("b", "b"); assertEquals(1, subPath.size()); assertEquals(1, subPath.objects().size()); assertEquals(1, subPath.labels().size()); assertEquals("stephen", subPath.objects().get(0)); /// subPath = path.subPath("b", "b"); assertEquals(1, subPath.size()); assertEquals(1, subPath.objects().size()); assertEquals(1, subPath.labels().size()); assertEquals("stephen", subPath.objects().get(0)); /// subPath = path.subPath("c", "d"); assertEquals(2, subPath.size()); assertEquals(2, subPath.objects().size()); assertEquals(2, subPath.labels().size()); assertEquals("matthias", subPath.objects().get(0)); assertEquals("bob", subPath.objects().get(1)); assertTrue(subPath.labels().get(0).contains("c")); assertTrue(subPath.labels().get(0).contains("x")); assertEquals(2, subPath.labels().get(0).size()); assertTrue(subPath.labels().get(1).contains("d")); assertEquals(1, subPath.labels().get(1).size()); /// subPath = path.subPath("c", null); assertEquals(2, subPath.size()); assertEquals(2, subPath.objects().size()); assertEquals(2, subPath.labels().size()); assertEquals("matthias", subPath.objects().get(0)); assertEquals("bob", subPath.objects().get(1)); assertTrue(subPath.labels().get(0).contains("c")); assertTrue(subPath.labels().get(0).contains("x")); assertEquals(2, subPath.labels().get(0).size()); assertTrue(subPath.labels().get(1).contains("d")); assertEquals(1, subPath.labels().get(1).size()); /// subPath = path.subPath("a", "d"); assertEquals(4, subPath.size()); assertEquals(4, subPath.objects().size()); assertEquals(4, subPath.labels().size()); /// subPath = path.subPath(null, "d"); assertEquals(4, subPath.size()); assertEquals(4, subPath.objects().size()); assertEquals(4, subPath.labels().size()); /// try { subPath = path.subPath("d", "a"); fail("Path labels must be ordered along path"); } catch (final IllegalArgumentException e) { assertEquals(Path.Exceptions.couldNotIsolatedSubPath("d", "a").getMessage(), e.getMessage()); } /// try { subPath = path.subPath("a", "e"); fail("End path label was not found"); } catch (final IllegalArgumentException e) { assertEquals(Path.Exceptions.couldNotLocatePathToLabel("e").getMessage(), e.getMessage()); } /// try { subPath = path.subPath("e", "b"); fail("Start path label was not found"); } catch (final IllegalArgumentException e) { assertEquals(Path.Exceptions.couldNotLocatePathFromLabel("e").getMessage(), e.getMessage()); } }); } @Test public void shouldHaveSubPathPopSupport() { PATH_SUPPLIERS.forEach(supplier -> { Path path = supplier.get(); path = path.extend("marko", Collections.singleton("a")); path = path.extend("stephen", Collections.singleton("a")); path = path.extend("matthias", new HashSet<>(Arrays.asList("c", "x"))); path = path.extend("bob", Collections.singleton("c")); assertEquals(4, path.size()); assertEquals(4, path.objects().size()); assertEquals(4, path.labels().size()); /// Path subPath = path.subPath("a", "c"); assertEquals(3, subPath.size()); assertEquals(3, subPath.objects().size()); assertEquals(3, subPath.labels().size()); assertEquals("stephen", subPath.objects().get(0)); assertEquals("matthias", subPath.objects().get(1)); assertEquals("bob", subPath.objects().get(2)); assertTrue(subPath.labels().get(0).contains("a")); assertEquals(1, subPath.labels().get(0).size()); assertTrue(subPath.labels().get(1).contains("c")); assertTrue(subPath.labels().get(1).contains("x")); assertEquals(2, subPath.labels().get(1).size()); assertTrue(subPath.labels().get(2).contains("c")); assertEquals(1, subPath.labels().get(2).size()); }); } }