/*
 * 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.step.filter;

import org.apache.tinkerpop.gremlin.FeatureRequirement;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.TextP;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW;
import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

/**
 * @author Marko A. Rodriguez (http://markorodriguez.com)
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
@RunWith(GremlinProcessRunner.class)
public abstract class HasTest extends AbstractGremlinProcessTest {

    public abstract Traversal<Vertex, String> get_g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name();

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_hasXkeyX(final Object v1Id, final String key);

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_hasXname_markoX(final Object v1Id);

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_markoX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_blahX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXblahX();

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_hasXage_gt_30X(final Object v1Id);

    public abstract Traversal<Vertex, Vertex> get_g_VXv1X_hasXage_gt_30X(final Object v1Id);

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_out_hasXid_lt_3X(final Object v1Id, final Object v3Id);

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_out_hasIdX2X(final Object v1Id, final Object v2Id);

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_out_hasIdX2_3X(final Object v1Id, final Object v2Id, final Object v3Id);

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXage_gt_30X();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXage_isXgt_30XX();

    public abstract Traversal<Edge, Edge> get_g_EX7X_hasLabelXknowsX(final Object e7Id);

    public abstract Traversal<Edge, Edge> get_g_E_hasLabelXknowsX();

    public abstract Traversal<Edge, Edge> get_g_EX11X_outV_outE_hasXid_10X(final Object e11Id, final Object e8Id);

    public abstract Traversal<Edge, Edge> get_g_E_hasLabelXuses_traversesX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasLabelXperson_software_blahX();

    public abstract Traversal<Vertex, Integer> get_g_V_hasXperson_name_markoX_age();

    public abstract Traversal<Vertex, Vertex> get_g_VX1X_outE_hasXweight_inside_0_06X_inV(final Object v1Id);

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXlocationX();

    public abstract Traversal<Vertex, Vertex> get_g_V_in_hasIdXneqX1XX(final Object v1Id);

    public abstract Traversal<Vertex, String> get_g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name();

    public abstract Traversal<Vertex, Integer> get_g_V_both_properties_dedup_hasKeyXageX_value();

    public abstract Traversal<Vertex, Integer> get_g_V_both_properties_dedup_hasKeyXageX_hasValueXgtX30XX_value();

    public abstract Traversal<Vertex, String> get_g_V_hasNotXageX_name();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasIdX1X_hasIdX2X(final Object v1Id, final Object v2Id);

    public abstract Traversal<Vertex, Vertex> get_g_V_hasLabelXpersonX_hasLabelXsoftwareX();

    public abstract Traversal<Vertex, Long> get_g_V_hasIdXemptyX_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasIdXwithinXemptyXX_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasIdXwithoutXemptyXX_count();

    public abstract Traversal<Vertex, Long> get_g_V_notXhasIdXwithinXemptyXXX_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasXage_withinX27X_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasXage_withinX27_29X_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasXage_withoutX27X_count();

    public abstract Traversal<Vertex, Long> get_g_V_hasXage_withoutX27_29X_count();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_containingXarkXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_startingWithXmarXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_endingWithXasXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_not_containingXarkXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_not_startingWithXmarXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_not_endingWithXasXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXperson_name_containingXoX_andXltXmXXX();

    public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_gtXmX_andXcontainingXoXXX();

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name() {
        final Traversal<Vertex, String> traversal = get_g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name();
        printTraversalForm(traversal);
        checkResults(Arrays.asList("ripple"), traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_hasXnameX() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_hasXkeyX(convertToVertexId("marko"), "name");
        printTraversalForm(traversal);
        assertEquals("marko", traversal.next().<String>value("name"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_hasXcircumferenceX() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_hasXkeyX(convertToVertexId("marko"), "circumference");
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_hasXname_markoX() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_hasXname_markoX(convertToVertexId("marko"));
        printTraversalForm(traversal);
        assertEquals("marko", traversal.next().<String>value("name"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX2X_hasXname_markoX() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_hasXname_markoX(convertToVertexId("vadas"));
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_markoX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_markoX();
        printTraversalForm(traversal);
        assertEquals("marko", traversal.next().<String>value("name"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_blahX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_blahX();
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_gt_30X() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXage_gt_30X();
        printTraversalForm(traversal);
        final List<Vertex> list = traversal.toList();
        assertEquals(2, list.size());
        for (final Element v : list) {
            assertTrue(v.<Integer>value("age") > 30);
        }
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_isXgt_30XX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXage_isXgt_30XX();
        printTraversalForm(traversal);
        final List<Vertex> list = traversal.toList();
        assertEquals(2, list.size());
        for (final Element v : list) {
            assertTrue(v.<Integer>value("age") > 30);
        }
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_hasXage_gt_30X() {
        final Traversal<Vertex, Vertex> traversalMarko = get_g_VX1X_hasXage_gt_30X(convertToVertexId("marko"));
        printTraversalForm(traversalMarko);
        assertFalse(traversalMarko.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX4X_hasXage_gt_30X() {
        final Traversal<Vertex, Vertex> traversalJosh = get_g_VX1X_hasXage_gt_30X(convertToVertexId("josh"));
        printTraversalForm(traversalJosh);
        assertTrue(traversalJosh.hasNext());
        traversalJosh.iterate();
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VXv1X_hasXage_gt_30X() {
        final Traversal<Vertex, Vertex> traversalMarko = get_g_VXv1X_hasXage_gt_30X(convertToVertex(graph,"marko"));
        printTraversalForm(traversalMarko);
        assertFalse(traversalMarko.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VXv4X_hasXage_gt_30X() {
        final Traversal<Vertex, Vertex> traversalJosh = get_g_VXv1X_hasXage_gt_30X(convertToVertex(graph,"josh"));
        printTraversalForm(traversalJosh);
        assertTrue(traversalJosh.hasNext());
        traversalJosh.iterate();
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_out_hasXid_2X() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_out_hasIdX2X(convertToVertexId("marko"), convertToVertexId("vadas"));
        assertVadasAsOnlyValueReturned(traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_USER_SUPPLIED_IDS)
    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NUMERIC_IDS)
    public void g_VX1X_out_hasXid_lt_3X() {
        // can only execute this on graphs with user supplied ids so that we can be assured of the lt op. it
        // sort of assumes that ids increment, but there's no feature check for that.  graphs that don't work this
        // way with numeric ids may need to optout
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_out_hasXid_lt_3X(convertToVertexId("marko"), convertToVertexId("lop"));
        assertVadasAsOnlyValueReturned(traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1AsStringX_out_hasXid_2AsStringX() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_out_hasIdX2X(convertToVertexId("marko").toString(), convertToVertexId("vadas").toString());
        assertVadasAsOnlyValueReturned(traversal);
    }

    private void assertVadasAsOnlyValueReturned(final Traversal<Vertex, Vertex> traversal) {
        printTraversalForm(traversal);
        assertThat(traversal.hasNext(), is(true));
        assertEquals(convertToVertexId("vadas"), traversal.next().id());
        assertThat(traversal.hasNext(), is(false));
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_out_hasXid_2_3X() {
        final Object id2 = convertToVertexId("vadas");
        final Object id3 = convertToVertexId("lop");
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_out_hasIdX2_3X(convertToVertexId("marko"), id2, id3);
        assert_g_VX1X_out_hasXid_2_3X(id2, id3, traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_out_hasXid_2AsString_3AsStringX() {
        final Object id2 = convertToVertexId("vadas");
        final Object id3 = convertToVertexId("lop");
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_out_hasIdX2_3X(convertToVertexId("marko"), id2.toString(), id3.toString());
        assert_g_VX1X_out_hasXid_2_3X(id2, id3, traversal);
    }

    protected void assert_g_VX1X_out_hasXid_2_3X(Object id2, Object id3, Traversal<Vertex, Vertex> traversal) {
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertThat(traversal.next().id(), CoreMatchers.anyOf(is(id2), is(id3)));
        assertThat(traversal.next().id(), CoreMatchers.anyOf(is(id2), is(id3)));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXblahX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXblahX();
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }


    @Test
    @LoadGraphWith(MODERN)
    public void g_EX7X_hasXlabelXknowsX() {
        final Traversal<Edge, Edge> traversal = get_g_EX7X_hasLabelXknowsX(convertToEdgeId("marko", "knows", "vadas"));
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            assertEquals("knows", traversal.next().label());
        }
        assertEquals(1, counter);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_E_hasXlabelXknowsX() {
        final Traversal<Edge, Edge> traversal = get_g_E_hasLabelXknowsX();
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            assertEquals("knows", traversal.next().label());
        }
        assertEquals(2, counter);
    }

    @Test
    @LoadGraphWith(CREW)
    public void g_E_hasLabelXuses_traversesX() {
        final Traversal<Edge, Edge> traversal = get_g_E_hasLabelXuses_traversesX();
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            final String label = traversal.next().label();
            assertTrue(label.equals("uses") || label.equals("traverses"));
        }
        assertEquals(9, counter);
    }

    @Test
    @LoadGraphWith(CREW)
    public void g_V_hasLabelXperson_software_blahX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasLabelXperson_software_blahX();
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            final String label = traversal.next().label();
            assertTrue(label.equals("software") || label.equals("person"));
        }
        assertEquals(6, counter);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXperson_name_markoX_age() {
        final Traversal<Vertex, Integer> traversal = get_g_V_hasXperson_name_markoX_age();
        printTraversalForm(traversal);
        assertEquals(29, traversal.next().intValue());
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_VX1X_outE_hasXweight_inside_0_06X_inV() {
        final Traversal<Vertex, Vertex> traversal = get_g_VX1X_outE_hasXweight_inside_0_06X_inV(convertToVertexId("marko"));
        printTraversalForm(traversal);
        while (traversal.hasNext()) {
            Vertex vertex = traversal.next();
            assertTrue(vertex.value("name").equals("vadas") || vertex.value("name").equals("lop"));
        }
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_EX11X_outV_outE_hasXid_10X() {
        final Object edgeId11 = convertToEdgeId("josh", "created", "lop");
        final Object edgeId10 = convertToEdgeId("josh", "created", "ripple");
        final Traversal<Edge, Edge> traversal = get_g_EX11X_outV_outE_hasXid_10X(edgeId11, edgeId10);
        printTraversalForm(traversal);
        assert_g_EX11X(edgeId10, traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_EX11X_outV_outE_hasXid_10AsStringX() {
        final Object edgeId11 = convertToEdgeId("josh", "created", "lop");
        final Object edgeId10 = convertToEdgeId("josh", "created", "ripple");
        final Traversal<Edge, Edge> traversal = get_g_EX11X_outV_outE_hasXid_10X(edgeId11.toString(), edgeId10.toString());
        printTraversalForm(traversal);
        assert_g_EX11X(edgeId10, traversal);
    }

    @Test
    @LoadGraphWith(CREW)
    public void g_V_hasXlocationX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXlocationX();
        printTraversalForm(traversal);
        checkResults(Arrays.asList(convertToVertex(graph, "marko"), convertToVertex(graph, "stephen"), convertToVertex(graph, "daniel"), convertToVertex(graph, "matthias")), traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name() {
        final Traversal<Vertex, String> traversal = get_g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name();
        printTraversalForm(traversal);
        checkResults(Arrays.asList("peter", "vadas"), traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_in_hasIdXneqX1XX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_in_hasIdXneqX1XX(convertToVertexId("marko"));
        printTraversalForm(traversal);
        int count = 0;
        while (traversal.hasNext()) {
            Vertex vertex = traversal.next();
            assertTrue(vertex.value("name").equals("josh") || vertex.value("name").equals("peter"));
            count++;
        }
        assertEquals(3, count);
    }

    private void assert_g_EX11X(final Object edgeId, final Traversal<Edge, Edge> traversal) {
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        final Edge e = traversal.next();
        assertEquals(edgeId, e.id());
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_both_dedup_properties_hasKeyXageX_value() {
        final Traversal<Vertex, Integer> traversal = get_g_V_both_properties_dedup_hasKeyXageX_value();
        printTraversalForm(traversal);
        checkResults(Arrays.asList(29, 27, 32, 35), traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_both_dedup_properties_hasKeyXageX_hasValueXgtX30XX_value() {
        final Traversal<Vertex, Integer> traversal = get_g_V_both_properties_dedup_hasKeyXageX_hasValueXgtX30XX_value();
        printTraversalForm(traversal);
        checkResults(Arrays.asList(32, 35), traversal);
    }

    @Test
    @LoadGraphWith
    public void g_V_hasNotXageX_name() {
        final Traversal<Vertex, String> traversal = get_g_V_hasNotXageX_name();
        printTraversalForm(traversal);
        checkResults(Arrays.asList("lop", "ripple"), traversal);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasIdX1X_hasIdX2X() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasIdX1X_hasIdX2X(
                convertToVertexId("marko"), convertToVertexId("vadas")
        );
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasLabelXpersonX_hasLabelXsoftwareX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasLabelXpersonX_hasLabelXsoftwareX();
        printTraversalForm(traversal);
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasIdXemptyX_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasIdXemptyX_count();
        printTraversalForm(traversal);
        assertEquals(0L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasIdXwithinXemptyXX_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasIdXwithinXemptyXX_count();
        printTraversalForm(traversal);
        assertEquals(0L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasIdXwithoutXemptyXX_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasIdXwithoutXemptyXX_count();
        printTraversalForm(traversal);
        assertEquals(6L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_notXhasIdXwithinXemptyXXX_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_notXhasIdXwithinXemptyXXX_count();
        printTraversalForm(traversal);
        assertEquals(6L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_withinX27X_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasXage_withinX27X_count();
        printTraversalForm(traversal);
        assertEquals(1L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_withinX27_29X_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasXage_withinX27_29X_count();
        printTraversalForm(traversal);
        assertEquals(2L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_withoutX27X_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasXage_withoutX27X_count();
        printTraversalForm(traversal);
        assertEquals(3L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXage_withoutX27_29X_count() {
        final Traversal<Vertex, Long> traversal = get_g_V_hasXage_withoutX27_29X_count();
        printTraversalForm(traversal);
        assertEquals(2L, traversal.next().longValue());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_containingXarkXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_containingXarkXX();
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertTrue(traversal.next().value("name").equals("marko"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_startingWithXmarXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_startingWithXmarXX();
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertTrue(traversal.next().value("name").equals("marko"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_endingWithXasXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_endingWithXasXX();
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertTrue(traversal.next().value("name").equals("vadas"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_not_containingXarkXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_not_containingXarkXX();
        printTraversalForm(traversal);

        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            assertNotEquals("marko", traversal.next().value("name"));
        }
        assertEquals(5, counter);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_not_startingWithXmarXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_not_startingWithXmarXX();
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            assertNotEquals("marko", traversal.next().value("name"));
        }
        assertEquals(5, counter);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_not_endingWithXasXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_not_endingWithXasXX();
        printTraversalForm(traversal);
        int counter = 0;
        while (traversal.hasNext()) {
            counter++;
            assertNotEquals("vadas", traversal.next().value("name"));
        }
        assertEquals(5, counter);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXperson_name_containingXoX_andXltXmXXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXperson_name_containingXoX_andXltXmXXX();
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertTrue(traversal.next().value("name").equals("josh"));
        assertFalse(traversal.hasNext());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_hasXname_gtXmX_andXcontainingXoXXX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_gtXmX_andXcontainingXoXXX();
        printTraversalForm(traversal);
        assertTrue(traversal.hasNext());
        assertTrue(traversal.next().value("name").equals("marko"));
        assertFalse(traversal.hasNext());
    }

    public static class Traversals extends HasTest {
        @Override
        public Traversal<Edge, Edge> get_g_EX11X_outV_outE_hasXid_10X(final Object e11Id, final Object e10Id) {
            return g.E(e11Id).outV().outE().has(T.id, e10Id);
        }

        @Override
        public Traversal<Vertex, String> get_g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name() {
            return g.V().out("created").has("name", __.<String, Integer>map(s -> s.get().length()).is(P.gt(3))).values("name");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_hasXkeyX(final Object v1Id, final String key) {
            return g.V(v1Id).has(key);
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_hasXname_markoX(final Object v1Id) {
            return g.V(v1Id).has("name", "marko");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_markoX() {
            return g.V().has("name", "marko");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_blahX() {
            return g.V().has("name", "blah");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXblahX() {
            return g.V().has("blah");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_hasXage_gt_30X(final Object v1Id) {
            return g.V(v1Id).has("age", P.gt(30));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VXv1X_hasXage_gt_30X(final Object v1Id) {
            return g.V(v1Id).has("age", P.gt(30));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_out_hasXid_lt_3X(final Object v1Id, final Object v3Id) {
            return g.V(v1Id).out().has(T.id, P.lt(v3Id));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_out_hasIdX2X(final Object v1Id, final Object v2Id) {
            return g.V(v1Id).out().hasId(v2Id);
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_out_hasIdX2_3X(final Object v1Id, final Object v2Id, final Object v3Id) {
            return g.V(v1Id).out().hasId(v2Id, v3Id);
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXage_gt_30X() {
            return g.V().has("age", P.gt(30));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXage_isXgt_30XX() {
            return g.V().has("age", __.is(P.gt(30)));
        }

        @Override
        public Traversal<Edge, Edge> get_g_EX7X_hasLabelXknowsX(final Object e7Id) {
            return g.E(e7Id).hasLabel("knows");
        }

        @Override
        public Traversal<Edge, Edge> get_g_E_hasLabelXknowsX() {
            return g.E().hasLabel("knows");
        }

        @Override
        public Traversal<Edge, Edge> get_g_E_hasLabelXuses_traversesX() {
            return g.E().hasLabel("uses", "traverses");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasLabelXperson_software_blahX() {
            return g.V().hasLabel("person", "software", "blah");
        }

        @Override
        public Traversal<Vertex, Integer> get_g_V_hasXperson_name_markoX_age() {
            return g.V().has("person", "name", "marko").values("age");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_VX1X_outE_hasXweight_inside_0_06X_inV(final Object v1Id) {
            return g.V(v1Id).outE().has("weight", P.inside(0.0d, 0.6d)).inV();
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXlocationX() {
            return g.V().has("location");
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_in_hasIdXneqX1XX(final Object v1Id) {
            return g.V().in().hasId(P.neq(v1Id));
        }

        @Override
        public Traversal<Vertex, String> get_g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name() {
            return g.V().hasLabel("person").has("age", P.not(P.lte(10).and(P.not(P.between(11, 20)))).and(P.lt(29).or(P.eq(35)))).values("name");
        }

        @Override
        public Traversal<Vertex, Integer> get_g_V_both_properties_dedup_hasKeyXageX_value() {
            return g.V().both().properties().dedup().hasKey("age").value();
        }

        @Override
        public Traversal<Vertex, Integer> get_g_V_both_properties_dedup_hasKeyXageX_hasValueXgtX30XX_value() {
            return g.V().both().properties().dedup().hasKey("age").hasValue(P.gt(30)).value();
        }

        @Override
        public Traversal<Vertex, String> get_g_V_hasNotXageX_name() {
            return g.V().hasNot("age").values("name");
        }

        @Override
        public Traversal<Vertex, Vertex>  get_g_V_hasIdX1X_hasIdX2X(final Object v1Id, final Object v2Id) {
            return g.V().hasId(v1Id).hasId(v2Id);
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasLabelXpersonX_hasLabelXsoftwareX() {
            return g.V().hasLabel("person").hasLabel("software");
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasIdXemptyX_count() {
            return g.V().hasId(Collections.emptyList()).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasIdXwithinXemptyXX_count() {
            return g.V().hasId(P.within(Collections.emptyList())).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasIdXwithoutXemptyXX_count() {
            return g.V().hasId(P.without(Collections.emptyList())).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_notXhasIdXwithinXemptyXXX_count() {
            return g.V().not(__.hasId(P.within(Collections.emptyList()))).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasXage_withinX27X_count() {
            return g.V().has("age", P.within(27)).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasXage_withinX27_29X_count() {
            return g.V().has("age", P.within(27, 29)).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasXage_withoutX27X_count() {
            return g.V().has("age", P.without(27)).count();
        }

        @Override
        public Traversal<Vertex, Long> get_g_V_hasXage_withoutX27_29X_count() {
            return g.V().has("age", P.without(27, 29)).count();
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_containingXarkXX() {
            return g.V().has("name", TextP.containing("ark"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_startingWithXmarXX() {
            return g.V().has("name", TextP.startingWith("mar"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_endingWithXasXX() {
            return g.V().has("name", TextP.endingWith("as"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_not_containingXarkXX() {
            return g.V().has("name", TextP.notContaining("ark"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_not_startingWithXmarXX() {
            return g.V().has("name", TextP.notStartingWith("mar"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_not_endingWithXasXX() {
            return g.V().has("name", TextP.notEndingWith("as"));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXperson_name_containingXoX_andXltXmXXX() {
            return g.V().has("person","name", TextP.containing("o").and(P.lt("m")));
        }

        @Override
        public Traversal<Vertex, Vertex> get_g_V_hasXname_gtXmX_andXcontainingXoXXX() {
            return g.V().has("name", P.gt("m").and(TextP.containing("o")));
        }
    }
}