blob: 84b6e9a8381c35f6d35f0cd24c39dc91cda1696a [file] [log] [blame]
/*
* 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.computer.Computer;
import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
import org.apache.tinkerpop.gremlin.structure.Column;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public class BytecodeTest {
@Test
public void shouldHaveProperHashAndEquality() {
final GraphTraversalSource g = EmptyGraph.instance().traversal();
final Traversal.Admin traversal1 = g.V().out().repeat(__.out().in()).times(2).groupCount().by(__.outE().count()).select(Column.keys).order().by(Order.desc).asAdmin();
final Traversal.Admin traversal2 = g.V().out().repeat(__.out().in()).times(2).groupCount().by(__.outE().count()).select(Column.keys).order().by(Order.desc).asAdmin();
final Traversal.Admin traversal3 = g.V().out().repeat(__.out().in()).times(2).groupCount().by(__.outE().count()).select(Column.values).order().by(Order.desc).asAdmin();
assertEquals(traversal1, traversal2);
assertNotEquals(traversal1, traversal3);
assertNotEquals(traversal2, traversal3);
//
assertEquals(traversal1.hashCode(), traversal2.hashCode());
assertNotEquals(traversal1.hashCode(), traversal3.hashCode());
assertNotEquals(traversal2.hashCode(), traversal3.hashCode());
//
assertEquals(traversal1.getBytecode(), traversal2.getBytecode());
assertNotEquals(traversal1.getBytecode(), traversal3.getBytecode());
assertNotEquals(traversal2.getBytecode(), traversal3.getBytecode());
//
assertEquals(traversal1.getBytecode().hashCode(), traversal2.getBytecode().hashCode());
assertNotEquals(traversal1.getBytecode().hashCode(), traversal3.getBytecode().hashCode());
assertNotEquals(traversal2.getBytecode().hashCode(), traversal3.getBytecode().hashCode());
}
@Test
public void shouldCloneCorrectly() {
final GraphTraversalSource g = EmptyGraph.instance().traversal();
final Bytecode bytecode = g.V().out().asAdmin().getBytecode();
final Bytecode bytecodeClone = bytecode.clone();
assertEquals(bytecode, bytecodeClone);
assertEquals(bytecode.hashCode(), bytecodeClone.hashCode());
bytecodeClone.addStep("in", "created"); // mutate the clone and the original should stay the same
assertNotEquals(bytecode, bytecodeClone);
assertNotEquals(bytecode.hashCode(), bytecodeClone.hashCode());
assertEquals(2, IteratorUtils.count(bytecode.getInstructions()));
assertEquals(3, IteratorUtils.count(bytecodeClone.getInstructions()));
}
@Test
public void shouldIncludeBindingsInEquality() {
final Bindings b = Bindings.instance();
final GraphTraversalSource g = EmptyGraph.instance().traversal();
final Bytecode bytecode1 = g.V().out(b.of("a", "created")).asAdmin().getBytecode();
final Bytecode bytecode2 = g.V().out(b.of("a", "knows")).asAdmin().getBytecode();
final Bytecode bytecode3 = g.V().out(b.of("b", "knows")).asAdmin().getBytecode();
final Bytecode bytecode4 = g.V().out(b.of("b", "knows")).asAdmin().getBytecode();
assertNotEquals(bytecode1, bytecode2);
assertNotEquals(bytecode1, bytecode3);
assertNotEquals(bytecode2, bytecode3);
assertNotEquals(bytecode2, bytecode4);
assertNotEquals(bytecode1, bytecode4);
assertEquals(bytecode3, bytecode4);
assertEquals(1, bytecode1.getBindings().size());
assertEquals("created", bytecode1.getBindings().get("a"));
}
@Test
public void shouldIncludeBindingsInNestedTraversals() {
final Bindings b = Bindings.instance();
final GraphTraversalSource g = EmptyGraph.instance().traversal();
final Bytecode bytecode = g.V().in(b.of("a","created")).where(__.out(b.of("b","knows")).has("age",b.of("c",P.gt(32))).map(__.values(b.of("d","name")))).asAdmin().getBytecode();
assertEquals(4, bytecode.getBindings().size());
assertEquals("created", bytecode.getBindings().get("a"));
assertEquals("knows", bytecode.getBindings().get("b"));
assertEquals(P.gt(32), bytecode.getBindings().get("c"));
assertEquals("name", bytecode.getBindings().get("d"));
//
Bytecode.Binding binding = (Bytecode.Binding)((List<Bytecode.Instruction>)bytecode.getStepInstructions()).get(1).getArguments()[0];
assertEquals("a", binding.variable());
assertEquals("created", binding.value());
binding = (Bytecode.Binding) ((List<Bytecode.Instruction>)((Bytecode)((List<Bytecode.Instruction>)bytecode.getStepInstructions()).get(2).getArguments()[0]).getStepInstructions()).get(0).getArguments()[0];
assertEquals("b", binding.variable());
assertEquals("knows", binding.value());
binding = (Bytecode.Binding) ((List<Bytecode.Instruction>)((Bytecode)((List<Bytecode.Instruction>)bytecode.getStepInstructions()).get(2).getArguments()[0]).getStepInstructions()).get(1).getArguments()[1];
assertEquals("c", binding.variable());
assertEquals(P.gt(32), binding.value());
binding = (Bytecode.Binding) ((List<Bytecode.Instruction>)((Bytecode)((List<Bytecode.Instruction>)((Bytecode)((List<Bytecode.Instruction>)bytecode.getStepInstructions()).get(2).getArguments()[0]).getStepInstructions()).get(2).getArguments()[0]).getStepInstructions()).get(0).getArguments()[0];
assertEquals("d", binding.variable());
assertEquals("name", binding.value());
}
@Test
public void shouldConvertStrategies() {
final GraphTraversalSource g = EmptyGraph.instance().traversal();
Bytecode bytecode = g.withStrategies(ReadOnlyStrategy.instance()).getBytecode();
assertEquals(ReadOnlyStrategy.instance(), bytecode.getSourceInstructions().get(0).getArguments()[0]);
bytecode = g.withStrategies(SubgraphStrategy.build().edges(__.hasLabel("knows")).create()).getBytecode();
assertEquals(SubgraphStrategy.build().edges(__.hasLabel("knows")).create().getEdgeCriterion().asAdmin().getBytecode(),
((SubgraphStrategy) bytecode.getSourceInstructions().iterator().next().getArguments()[0]).getEdgeCriterion().asAdmin().getBytecode());
}
@Test
public void shouldConvertComputer() {
final GraphTraversalSource g = EmptyGraph.instance().traversal();
Bytecode bytecode = g.withComputer(Computer.compute().workers(10)).getBytecode();
assertEquals(VertexProgramStrategy.build().create(), bytecode.getSourceInstructions().get(0).getArguments()[0]);
assertEquals(VertexProgramStrategy.build().workers(10).create().getConfiguration().getInt(VertexProgramStrategy.WORKERS),
((VertexProgramStrategy) bytecode.getSourceInstructions().iterator().next().getArguments()[0]).getConfiguration().getInt(VertexProgramStrategy.WORKERS));
}
@Test
public void shouldNotHaveHashCollisionsWithBindings() {
// ideally we should be using guava's EqualsTester to test equals/hashCode but the equals/hashCode contract allows hash collisions.
// Yet we should avoid hash collisions in case these objects are being used in data structures that rely on hashCode
final Bytecode.Binding<String> first = new Bytecode.Binding<>("3", "7");
final Bytecode.Binding<String> second = new Bytecode.Binding<>("7", "3");
assertNotEquals(first, second);
assertNotEquals(first.hashCode(), second.hashCode());
}
@Test
public void shouldNotHaveHashCollisions() {
// ideally we should be using guava's EqualsTester to test equals/hashCode but the equals/hashCode contract allows hash collisions.
// Yet we should avoid hash collisions in case these objects are being used in data structures that rely on hashCode
final Bytecode first = new Bytecode();
first.addSource("3", "7");
first.addStep("7", "3");
final Bytecode second = new Bytecode();
second.addSource("7", "3");
second.addStep("3", "7");
assertNotEquals(first, second);
assertNotEquals(first.hashCode(), second.hashCode());
}
@Test
public void shouldHandleArrays() {
final Bytecode b = new Bytecode();
b.addStep(GraphTraversal.Symbols.property, "k", new Object[] { new String[] {"A", "B", "C"}});
assertEquals(1, b.getStepInstructions().size());
assertEquals(2, b.getStepInstructions().get(0).getArguments().length);
}
@Test
public void shouldAvoidArgumentsNpe() {
final Bytecode first = new Bytecode();
try {
first.addSource("3", null);
first.addSource(TraversalSource.Symbols.withoutStrategies, null);
} catch (Exception e) {
e.getCause().printStackTrace(System.err);
}
}
}