This is an automated email from the ASF dual-hosted git repository.

andreac pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.8-dev by this push:
     new a6f77163ff https://issues.apache.org/jira/browse/TINKERPOP-3192 (#3212)
a6f77163ff is described below

commit a6f77163ffe5d1639aef3f2f3b897ee4b53679c1
Author: andreachild <[email protected]>
AuthorDate: Fri Sep 26 13:27:46 2025 -0700

    https://issues.apache.org/jira/browse/TINKERPOP-3192 (#3212)
    
    This changeset modifies the RepeatUnrollStrategy to use a more conservative 
approach for determining which repeat traversals are safe to unroll. 
Previously, the strategy would attempt to unroll most repeat loops. This caused 
unintentional traversal semantic changes when some steps were unrolled 
(especially barrier steps) when they were no longer executed in a child 
traversal within a parent traversal.
    
    Now, the strategy only applies to repeat traversals that contain specific 
steps: out(), in(), both(), inV(), outV(), otherV(), has(key, value). Repeat 
traversals containing other steps will no longer be unrolled.
---
 CHANGELOG.asciidoc                                 |   1 +
 docs/src/upgrade/release-3.8.x.asciidoc            |  89 +++++++++
 .../optimization/RepeatUnrollStrategy.java         |  49 +++--
 .../process/traversal/util/TraversalHelper.java    |  18 ++
 .../optimization/RepeatUnrollStrategyTest.java     | 140 ++++++++-----
 .../traversal/util/TraversalHelperTest.java        |  49 ++++-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  16 ++
 gremlin-go/driver/cucumber/gremlin.go              |  16 ++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  16 ++
 gremlin-python/src/main/python/radish/gremlin.py   |  16 ++
 .../integrated/RepeatUnrollStrategy.feature        | 221 +++++++++++++++++++++
 11 files changed, 564 insertions(+), 67 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index cff757fff7..b7e9040d93 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -109,6 +109,7 @@ This release also includes changes from <<release-3-7-XXX, 
3.7.XXX>>.
 * Updated `asString()` step to throw `IllegalArgumentException` with `null` 
inputs for casting step consistency
 * Renamed `MergeElementStep` to `MergeElementStep` as it is a base class to 
`mergeV()` and `mergeE()`.
 * Renamed `MergeStep` of `merge()` to `MergeElementStep` for consistency.
+* Modified `RepeatUnrollStrategy` to use a more conservative approach, only 
unrolling repeat loops containing safe navigation and filtering steps.
 
 == TinkerPop 3.7.0 (Gremfir Master of the Pan Flute)
 
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc 
b/docs/src/upgrade/release-3.8.x.asciidoc
index 8c42d99271..f55b5cac5e 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -733,6 +733,95 @@ some of the interfaces in the gremlin traversal engine. 
This has led to several
 As of 3.8.0 `with()` modulation of the following steps will no longer work: 
`addV()`, `addE()`, `property()`, `drop()`,
 `mergeV()`, and `mergeE()`.
 
+==== Stricter RepeatUnrollStrategy
+
+The `RepeatUnrollStrategy` has been updated to use a more conservative 
approach for determining which repeat traversals 
+are safe to unroll. Previously, the strategy would attempt to unroll most 
usages of `repeat()` used with `times()` 
+without `emit()`. This caused unintentional traversal semantic changes when 
some steps were unrolled (especially barrier 
+steps). 
+
+As of 3.8.0, the strategy will still only be applied if `repeat()` is used 
with `times()` without `emit()` but now only 
+applies to repeat traversals that contain exclusively safe, well-understood 
steps: `out()`, `in()`, `both()`, `inV()`, 
+`outV()`, `otherV()`, `has(key, value)`. 
+
+Repeat traversals containing other steps will no longer be unrolled. There may 
be some performance differences for 
+traversals that previously benefited from automatic unrolling but the 
consistency of semantics outweighs the performance 
+impact.
+
+===== Examples of Affected Traversals =====
+
+Usage of `limit()` inside `repeat()` is an example of a traversal that will no 
longer be unrolled. The following results 
+returned from the `modern` graph demonstrate the change of semantics if the 
`limit()` in `repeat()` were to be unrolled:
+
+[source,text]
+----
+gremlin> g.V().both().limit(1).both().limit(1)
+==>v[1]
+gremlin> 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().limit()).times(2)
+gremlin>
+----
+
+Another example is the usage of `aggregate()` inside `repeat()`. The following 
results returned from the `modern` graph 
+demonstrate the change of semantics if the `aggregate()` in `repeat()` were to 
be unrolled:
+
+[source,text]
+----
+gremlin> g.V().both().aggregate('x').both().aggregate('x').limit(10)
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[4]
+==>v[4]
+==>v[4]
+gremlin> 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().aggregate('x')).times(2).limit(10)
+==>v[1]
+==>v[1]
+==>v[1]
+==>v[4]
+==>v[6]
+==>v[5]
+==>v[3]
+==>v[3]
+==>v[2]
+==>v[4]
+----
+
+Other examples of affected traversals include (but are not limited to):
+
+[source,groovy]
+----
+g.V().repeat(out().limit(10)).times(3)
+g.V().repeat(in().order().by("name")).times(2)
+g.V().repeat(both().simplePath()).times(4)
+g.V().repeat(both().sample(1)).times(2)
+----
+
+===== Migration Strategies
+
+Before upgrading, analyze existing traversals which use `repeat()` with any 
steps other than `out()`, `in()`, `both()`,
+`inV()`, `outV()`, `otherV()`, `has(key, value)` and determine if the 
semantics of these traversals are as expected when 
+the `RepeatUnrollStrategy` is disabled using 
`withoutStrategies(RepeatUnrollStrategy)`. If the semantics are unexpected
+the traversal should be restructured to no longer use `repeat()` by manually 
unrolling the steps inside `repeat()` or by
+moving affected steps outside the `repeat()`.
+
+Example:
+
+[source,groovy]
+----
+// original traversal
+g.V().repeat(both().dedup()).times(2)
+// can be manually unrolled to
+g.V().both().dedup().both().dedup()
+// or dedup can be moved outside of repeat
+g.V().repeat(both()).times(2).dedup()
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3192[TINKERPOP-3192]
+
 === Upgrading for Providers
 
 ==== Graph System Providers
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
index 18481cd2c6..24af90837f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
@@ -19,34 +19,40 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import java.util.Set;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.LoopTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
-import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder;
 import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatStep;
-import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LoopsStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeOtherVertexStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStepContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
 /**
  * {@code RepeatUnrollStrategy} is an OLTP-only strategy that unrolls any 
{@link RepeatStep} if it uses a constant
- * number of loops ({@code times(x)}) and doesn't emit intermittent elements. 
If any of the following 3 steps appears
- * within the repeat-traversal, the strategy will not be applied:
+ * number of loops ({@code times(x)}) and doesn't emit intermittent elements. 
The strategy only applies to repeat
+ * traversals that contain exclusively safe, stateless steps from the allowed 
set:
  * <p/>
  * <ul>
- *     <li>{@link DedupGlobalStep}</li>
- *     <li>{@link LoopsStep}</li>
- *     <li>{@link LambdaHolder}</li>
+ *     <li>{@link VertexStepContract}</li>
+ *     <li>{@link EdgeVertexStep}</li>
+ *     <li>{@link EdgeOtherVertexStep}</li>
+ *     <li>{@link HasStep}</li>
+ *     <li>{@link RepeatStep} and {@link RepeatStep.RepeatEndStep}</li>
  * </ul>
+ * <p/>
+ * Steps that are not in this allowed set will prevent the strategy from being 
applied. This allowed set of steps is 
+ * intentionally conservative as there have been unintentional traversal 
semantics changes in the past when allowing a 
+ * large variety of steps (especially barriers). Only steps that can be safely 
executed outside the repeat (and not 
+ * modify semantics of the traversal) should be included. The allowed set can 
be expanded in future versions as 
+ * additional steps are verified to be safe.
+ * <p/>
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @example <pre>
@@ -56,8 +62,14 @@ import java.util.Set;
 public final class RepeatUnrollStrategy extends 
AbstractTraversalStrategy<TraversalStrategy.OptimizationStrategy> implements 
TraversalStrategy.OptimizationStrategy {
 
     private static final RepeatUnrollStrategy INSTANCE = new 
RepeatUnrollStrategy();
-    protected static final int MAX_BARRIER_SIZE = 2500;
-    private static final Set<Class> INVALIDATING_STEPS = new 
HashSet<>(Arrays.asList(LambdaHolder.class, LoopsStep.class));
+    static final int MAX_BARRIER_SIZE = 2500;
+    private static final Set<Class> ALLOWED_STEP_CLASSES = Set.of(
+            VertexStepContract.class,
+            EdgeVertexStep.class,
+            EdgeOtherVertexStep.class,
+            HasStep.class,
+            RepeatStep.class,
+            RepeatStep.RepeatEndStep.class);
 
     private RepeatUnrollStrategy() {
     }
@@ -73,10 +85,10 @@ public final class RepeatUnrollStrategy extends 
AbstractTraversalStrategy<Traver
         for (int i = 0; i < traversal.getSteps().size(); i++) {
             if (traversal.getSteps().get(i) instanceof RepeatStep) {
                 final RepeatStep<?> repeatStep = (RepeatStep) 
traversal.getSteps().get(i);
+
                 if (null == repeatStep.getEmitTraversal() && null != 
repeatStep.getRepeatTraversal() &&
                         repeatStep.getUntilTraversal() instanceof 
LoopTraversal && ((LoopTraversal) repeatStep.getUntilTraversal()).getMaxLoops() 
> 0 &&
-                        
!TraversalHelper.hasStepOfAssignableClassRecursively(Scope.global, 
DedupGlobalStep.class, repeatStep.getRepeatTraversal()) &&
-                        
!TraversalHelper.hasStepOfAssignableClassRecursively(INVALIDATING_STEPS, 
repeatStep.getRepeatTraversal())) {
+                        
TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(ALLOWED_STEP_CLASSES,
 repeatStep.getRepeatTraversal())) {
 
                     final Traversal.Admin<?, ?> repeatTraversal = 
repeatStep.getGlobalChildren().get(0);
                     
repeatTraversal.removeStep(repeatTraversal.getSteps().size() - 1); // removes 
the RepeatEndStep
@@ -90,7 +102,7 @@ public final class RepeatUnrollStrategy extends 
AbstractTraversalStrategy<Traver
 
                         // the addition of barriers is determined by the 
existence of LazyBarrierStrategy
                         if (lazyBarrierStrategyInstalled) {
-                            // only add a final NoOpBarrier is subsequent step 
is not a barrier
+                            // only add a final NoOpBarrier if subsequent step 
is not a barrier
                             // Don't add a barrier if this step is a barrier 
(prevents nested repeat adding the barrier multiple times)
                             Step step = traversal.getSteps().get(insertIndex);
                             if ((j != (loops - 1) || !(step.getNextStep() 
instanceof Barrier)) && !(step instanceof NoOpBarrierStep)) {
@@ -110,7 +122,6 @@ public final class RepeatUnrollStrategy extends 
AbstractTraversalStrategy<Traver
         }
     }
 
-
     public static RepeatUnrollStrategy instance() {
         return INSTANCE;
     }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index b66f3efca4..156f92bdb1 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -640,6 +640,24 @@ public final class TraversalHelper {
         return false;
     }
 
+    /**
+     * Checks if the traversal only has steps that are equal to or assignable 
from the given step classes.
+     *
+     * @param stepClasses the collection of allowed step classes
+     * @param traversal the traversal to check
+     * @return true if all steps in the traversal are equal to or assignable 
from the given classes
+     */
+    public static boolean hasOnlyStepsOfAssignableClassesRecursively(final 
Collection<Class> stepClasses, final Traversal.Admin<?, ?> traversal) {
+        for (final Step<?, ?> step : 
getStepsOfAssignableClassRecursively(Step.class, traversal)) {
+            final boolean isSupported = stepClasses.stream()
+                    .anyMatch(allowedClass -> 
allowedClass.isAssignableFrom(step.getClass()));
+            if (!isSupported) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Determine if any step in {@link Traversal} or its children match the 
step given the provided {@link Predicate}.
      *
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
index 1b1243c8f0..1bd2675346 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategyTest.java
@@ -43,6 +43,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.function.Predicate;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.path;
@@ -58,50 +59,17 @@ public class RepeatUnrollStrategyTest {
     @RunWith(Parameterized.class)
     public static class StandardTest {
         @Parameterized.Parameter(value = 0)
-        public Traversal.Admin<?,?> original;
+        public Traversal.Admin<?, ?> original;
 
         @Parameterized.Parameter(value = 1)
-        public Traversal<?,?> optimized;
+        public Traversal<?, ?> expectedOptimized;
 
         @Parameterized.Parameter(value = 2)
         public Collection<TraversalStrategy<?>> otherStrategies;
 
         @Test
-        public void doTest() {
-            final String repr = 
translator.translate(original.getBytecode()).getScript();
-            final TraversalStrategies strategiesWithLazy = new 
DefaultTraversalStrategies();
-            strategiesWithLazy.addStrategies(RepeatUnrollStrategy.instance());
-            Traversal.Admin<?, ?> clonedOriginal = this.original.clone();
-
-            // adding LazyBarrierStrategy as RepeatUnrollStrategy adds 
barriers and the existence of this strategy
-            // triggers those additions. if they are not there they will not 
be present and most of these assertions
-            // assume this strategy present
-            strategiesWithLazy.addStrategies(LazyBarrierStrategy.instance());
-            for (final TraversalStrategy<?> strategy : this.otherStrategies) {
-                strategiesWithLazy.addStrategies(strategy);
-            }
-            clonedOriginal.setStrategies(strategiesWithLazy);
-            clonedOriginal.applyStrategies();
-            assertEquals("With LazyBarrierStrategy: " + repr, this.optimized, 
clonedOriginal);
-
-            final TraversalStrategies strategiesWithoutLazy = new 
DefaultTraversalStrategies();
-            
strategiesWithoutLazy.addStrategies(RepeatUnrollStrategy.instance());
-            for (final TraversalStrategy<?> strategy : this.otherStrategies) {
-                strategiesWithoutLazy.addStrategies(strategy);
-            }
-            clonedOriginal = this.original.clone();
-            clonedOriginal.setStrategies(strategiesWithoutLazy);
-            clonedOriginal.applyStrategies();
-            final Traversal.Admin<?, ?> optimizedWithoutBarriers = 
this.optimized.asAdmin().clone();
-
-            // remove all the barriers as LazyBarrierStrategy is not present 
and therefore RepeatUnrollStrategy should
-            // not add any
-            
TraversalHelper.getStepsOfAssignableClassRecursively(NoOpBarrierStep.class, 
optimizedWithoutBarriers).forEach(s -> {
-                TraversalHelper.copyLabels(s, s.getPreviousStep(), true);
-                s.getTraversal().removeStep(s);
-            });
-            assertEquals("Without LazyBarrierStrategy: " + repr, 
optimizedWithoutBarriers, clonedOriginal);
-
+        public void testStrategyApplied() {
+            testRepeatUnrollStrategy(original, expectedOptimized, 
otherStrategies);
         }
 
         @Parameterized.Parameters(name = "{0}")
@@ -111,33 +79,68 @@ public class RepeatUnrollStrategyTest {
             final int repeatBarrierSize = 
RepeatUnrollStrategy.MAX_BARRIER_SIZE;
             final Predicate<Traverser<Vertex>> predicate = t -> t.loops() > 5;
             return Arrays.asList(new Object[][]{
-                    {__.repeat(out()).times(0), __.repeat(out()).times(0), 
Collections.emptyList()},
-                    {__.<Vertex>times(0).repeat(out()), 
__.<Vertex>times(0).repeat(out()), Collections.emptyList()},
-                    {__.identity(), __.identity(), Collections.emptyList()},
                     
{out().as("a").in().repeat(__.outE("created").bothV()).times(2).in(), 
out().as("a").in().outE("created").bothV().barrier(repeatBarrierSize).outE("created").bothV().barrier(repeatBarrierSize).in(),
 Collections.emptyList()},
                     {out().repeat(__.outE("created").bothV()).times(1).in(), 
out().outE("created").bothV().barrier(repeatBarrierSize).in(), 
Collections.emptyList()},
                     {__.repeat(__.outE("created").bothV()).times(1).in(), 
__.outE("created").bothV().barrier(repeatBarrierSize).in(), 
Collections.emptyList()},
                     
{__.repeat(out()).times(2).as("x").repeat(in().as("b")).times(3), 
out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize).as("x").in().as("b").barrier(repeatBarrierSize).in().as("b").barrier(repeatBarrierSize).in().as("b").barrier(repeatBarrierSize),
 Collections.emptyList()},
                     {__.repeat(__.outE("created").inV()).times(2), 
__.outE("created").inV().barrier(repeatBarrierSize).outE("created").inV().barrier(repeatBarrierSize),
 Collections.emptyList()},
                     {__.repeat(out()).times(3), 
out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize),
 Collections.emptyList()},
-                    
{__.repeat(__.local(__.select("a").out("knows"))).times(2), 
__.local(__.select("a").out("knows")).barrier(repeatBarrierSize).local(__.select("a").out("knows")).barrier(repeatBarrierSize),
 Collections.emptyList()},
                     {__.<Vertex>times(2).repeat(out()), 
out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize), 
Collections.emptyList()},
                     {__.<Vertex>out().times(2).repeat(out().as("a")).as("x"), 
out().out().as("a").barrier(repeatBarrierSize).out().as("a").barrier(repeatBarrierSize).as("x"),
 Collections.emptyList()},
-                    {__.repeat(out()).emit().times(2), 
__.repeat(out()).emit().times(2), Collections.emptyList()},
-                    {__.repeat(out()).until(predicate), 
__.repeat(out()).until(predicate), Collections.emptyList()},
                     {__.repeat(out()).until(predicate).repeat(out()).times(2), 
__.repeat(out()).until(predicate).out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize),
 Collections.emptyList()},
-                    {__.repeat(__.union(__.both(), 
__.identity())).times(2).out(), __.union(__.both(), 
__.identity()).barrier(repeatBarrierSize).union(__.both(), 
__.identity()).barrier(repeatBarrierSize).out(), Collections.emptyList()},
                     {in().repeat(out("knows")).times(3).as("a").count().is(0), 
in().out("knows").barrier(repeatBarrierSize).out("knows").barrier(repeatBarrierSize).out("knows").as("a").count().is(0),
 Collections.emptyList()},
                     //
                     {__.repeat(__.outE().inV()).times(2), 
__.outE().inV().barrier(repeatBarrierSize).outE().inV().barrier(repeatBarrierSize),
 Collections.emptyList()},
-                    {__.repeat(__.outE().filter(path()).inV()).times(2), 
__.outE().filter(path()).inV().barrier(repeatBarrierSize).outE().filter(path()).inV().barrier(repeatBarrierSize),
 Collections.singletonList(IncidentToAdjacentStrategy.instance())},
                     {__.repeat(__.outE().inV()).times(2), 
__.out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize), 
List.of(IncidentToAdjacentStrategy.instance(), 
GValueReductionStrategy.instance())},
                     // Nested Loop tests
                     {__.repeat(out().repeat(out()).times(0)).times(1), 
__.out().repeat(out()).times(0).barrier(repeatBarrierSize), 
Collections.emptyList()},
                     {__.repeat(out().repeat(out()).times(1)).times(1), 
__.out().out().barrier(repeatBarrierSize), Collections.emptyList()},
-                    
{__.repeat(out()).until(__.repeat(out()).until(predicate)), 
__.repeat(out()).until(__.repeat(out()).until(predicate)), 
Collections.emptyList()},
                     {__.repeat(__.repeat(out()).times(2)).until(predicate), 
__.repeat(__.out().barrier(repeatBarrierSize).out().barrier(repeatBarrierSize)).until(predicate),
 Collections.emptyList()},
-                    {__.repeat(__.repeat(out("created")).until(__.has("name", 
"ripple"))), __.repeat(__.repeat(out("created")).until(__.has("name", 
"ripple"))), Collections.emptyList()},
+                    // HasStep tests
+                    {__.repeat(out().has("name", "lop")).times(2), 
out().has("name", 
"lop").barrier(repeatBarrierSize).out().barrier(repeatBarrierSize).has("name", 
"lop").barrier(repeatBarrierSize), Collections.emptyList()},
+                    {__.repeat(in().has("age", 27)).times(3), in().has("age", 
27).barrier(repeatBarrierSize).in().barrier(repeatBarrierSize).has("age", 
27).barrier(repeatBarrierSize).in().barrier(repeatBarrierSize).has("age", 
27).barrier(repeatBarrierSize), Collections.emptyList()},
+                    {__.repeat(both().has("name", "marko")).times(2), 
both().has("name", 
"marko").barrier(repeatBarrierSize).both().barrier(repeatBarrierSize).has("name",
 "marko").barrier(repeatBarrierSize), Collections.emptyList()},
+                    // EdgeVertexStep tests  
+                    {__.repeat(__.outE().inV()).times(2), 
__.outE().inV().barrier(repeatBarrierSize).outE().inV().barrier(repeatBarrierSize),
 Collections.emptyList()},
+                    {__.repeat(__.inE().outV()).times(2), 
__.inE().outV().barrier(repeatBarrierSize).inE().outV().barrier(repeatBarrierSize),
 Collections.emptyList()},
+                    {__.repeat(__.bothE().otherV()).times(2), 
__.bothE().otherV().barrier(repeatBarrierSize).bothE().otherV().barrier(repeatBarrierSize),
 Collections.emptyList()},
+                    {__.repeat(__.outE("knows").otherV()).times(2), 
__.outE("knows").otherV().barrier(repeatBarrierSize).outE("knows").otherV().barrier(repeatBarrierSize),
 Collections.emptyList()},
+                    // Combined tests
+                    {__.repeat(__.outE("knows").inV().has("name", 
"josh")).times(2), __.outE("knows").inV().has("name", 
"josh").barrier(repeatBarrierSize).outE("knows").inV().barrier(repeatBarrierSize).has("name",
 "josh").barrier(repeatBarrierSize), Collections.emptyList()},
+            });
+        }
+    }
+
+    @RunWith(Parameterized.class)
+    public static class StrategyNotAppliedTest {
+        @Parameterized.Parameter(value = 0)
+        public Traversal.Admin<?, ?> original;
+
+        @Parameterized.Parameter(value = 1)
+        public Collection<TraversalStrategy<?>> otherStrategies;
+
+        @Test
+        public void testStrategyNotApplied() {
+            // since strategy should not have been applied, the optimized 
traversal is expected to be the same as the original
+            testRepeatUnrollStrategy(original, original, otherStrategies);
+        }
+
+        @Parameterized.Parameters(name = "{0}")
+        public static Iterable<Object[]> generateTestParameters() {
+            return Arrays.asList(new Object[][]{
+                    // zero loops
+                    {__.repeat(out()).times(0), Collections.emptyList()},
+                    {__.<Vertex>times(0).repeat(out()), 
Collections.emptyList()},
+                    // no repeat
+                    {__.identity(), Collections.emptyList()},
+                    // steps in repeat not candidates for unrolling
+                    
{__.repeat(__.local(__.select("a").out("knows"))).times(2), 
Collections.emptyList()},
+                    {__.repeat(__.union(__.both(), 
__.identity())).times(2).out(), Collections.emptyList()},
+                    {__.repeat(__.outE().filter(path()).inV()).times(2), 
Collections.singletonList(IncidentToAdjacentStrategy.instance())},
+                    // emit traversal is non-null
+                    {__.repeat(out()).emit().times(2), 
Collections.emptyList()},
+                    // until is not LoopsTraversal
+                    {__.repeat(out()).until(t -> t.loops() > 5), 
Collections.emptyList()},
             });
         }
     }
@@ -178,4 +181,47 @@ public class RepeatUnrollStrategyTest {
                     .variablesArePreserved();
         }
     }
+
+    /**
+     * Applies RepeatUnrollStrategy (with and without LazyBarrierStrategy) to 
the given original traversal and verifies the expected optimized traversal.
+     *
+     * @param original          the original traversal to apply strategies to
+     * @param expectedOptimized the expected optimized traversal
+     * @param otherStrategies   any other strategies that should also be 
applied
+     */
+    private static void testRepeatUnrollStrategy(Traversal.Admin<?, ?> 
original, Traversal<?, ?> expectedOptimized, Collection<TraversalStrategy<?>> 
otherStrategies) {
+        final String repr = 
translator.translate(original.getBytecode()).getScript();
+        final TraversalStrategies strategiesWithLazy = new 
DefaultTraversalStrategies();
+        strategiesWithLazy.addStrategies(RepeatUnrollStrategy.instance());
+        Traversal.Admin<?, ?> clonedOriginal = original.clone();
+
+        // adding LazyBarrierStrategy as RepeatUnrollStrategy adds barriers 
and the existence of this strategy
+        // triggers those additions. if they are not there they will not be 
present and most of these assertions
+        // assume this strategy present
+        strategiesWithLazy.addStrategies(LazyBarrierStrategy.instance());
+        for (final TraversalStrategy<?> strategy : otherStrategies) {
+            strategiesWithLazy.addStrategies(strategy);
+        }
+        clonedOriginal.setStrategies(strategiesWithLazy);
+        clonedOriginal.applyStrategies();
+        assertEquals("With LazyBarrierStrategy: " + repr, expectedOptimized, 
clonedOriginal);
+
+        final TraversalStrategies strategiesWithoutLazy = new 
DefaultTraversalStrategies();
+        strategiesWithoutLazy.addStrategies(RepeatUnrollStrategy.instance());
+        for (final TraversalStrategy<?> strategy : otherStrategies) {
+            strategiesWithoutLazy.addStrategies(strategy);
+        }
+        clonedOriginal = original.clone();
+        clonedOriginal.setStrategies(strategiesWithoutLazy);
+        clonedOriginal.applyStrategies();
+        final Traversal.Admin<?, ?> optimizedWithoutBarriers = 
expectedOptimized.asAdmin().clone();
+
+        // remove all the barriers as LazyBarrierStrategy is not present and 
therefore RepeatUnrollStrategy should
+        // not add any
+        
TraversalHelper.getStepsOfAssignableClassRecursively(NoOpBarrierStep.class, 
optimizedWithoutBarriers).forEach(s -> {
+            TraversalHelper.copyLabels(s, s.getPreviousStep(), true);
+            s.getTraversal().removeStep(s);
+        });
+        assertEquals("Without LazyBarrierStrategy: " + repr, 
optimizedWithoutBarriers, clonedOriginal);
+    }
 }
\ No newline at end of file
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
index 36b3673413..bacf17622e 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
@@ -39,10 +39,13 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversal
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NotStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FlatMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStepContract;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertiesStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStepContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.structure.PropertyType;
@@ -52,7 +55,6 @@ import org.junit.Test;
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -600,4 +602,49 @@ public class TraversalHelperTest {
         final List<Step<?,?>> steps = (List) 
TraversalHelper.getStepsOfClass(Step.class, t);
         assertEquals(0, steps.size());
     }
+
+    @Test
+    public void hasOnlyShouldReturnTrueWhenAllStepsAreAssignable() {
+        assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(
+                Set.of(GraphStep.class, VertexStep.class, HasStep.class),
+                __.V().out().has("name", "marko").asAdmin()), is(true));
+    }
+
+    @Test
+    public void hasOnlyShouldReturnFalseWhenStepNotAssignable() {
+        assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(
+                Set.of(GraphStep.class, VertexStep.class),
+                __.V().out().count().asAdmin()), is(false));
+    }
+
+    @Test
+    public void hasOnlyShouldWorkWithInterfaceClasses() {
+        assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(
+                Set.of(GraphStepContract.class, VertexStepContract.class),
+                __.V().out().asAdmin()), is(true));
+    }
+
+    @Test
+    public void hasOnlyShouldWorkRecursivelyWithNestedTraversals() {
+        assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(
+                Set.of(GraphStep.class, RepeatStep.class, 
RepeatStep.RepeatEndStep.class, VertexStep.class, HasStep.class),
+                __.V().repeat(__.out().has("name", 
"marko")).times(2).asAdmin()), is(true));
+    }
+
+    @Test
+    public void hasOnlyShouldReturnFalseForNestedTraversalWithDisallowedStep() 
{
+        assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(
+                Set.of(GraphStep.class, RepeatStep.class, VertexStep.class),
+                __.V().repeat(__.out().limit(1)).times(2).asAdmin()), 
is(false));
+    }
+
+    @Test
+    public void hasOnlyShouldReturnTrueForEmptyTraversal() {
+        
assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(Set.of(IdentityStep.class),
 __.identity().asAdmin()), is(true));
+    }
+
+    @Test
+    public void hasOnlyShouldReturnFalseForEmptyAllowedClasses() {
+        
assertThat(TraversalHelper.hasOnlyStepsOfAssignableClassesRecursively(Set.of(), 
__.V().out().asAdmin()), is(false));
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 278919abbf..032054180f 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -582,6 +582,22 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_withoutStrategiesXReferenceElementStrategyX_V", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithoutStrategies(typeof(ReferenceElementStrategy)).V()}}, 
                
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.Out()).Times(2)}}, 
                
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.Out()).Times(2)}},
 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.In()).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.In()).Times(2)}},
 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.Out().Has("name", 
TextP.NotStartingWith("z"))).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.Out().Has("name",
 TextP.NotStartingWith("z"))).Times(2)}}, 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.In().Has("age", P.Gt(20))).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.In().Has("age",
 P.Gt(20))).Times(2)}}, 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.Both().Has("age", P.Lt(30))).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.Both().Has("age",
 P.Lt(30))).Times(2)}}, 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.BothE().OtherV().Has("age", 
P.Lt(30))).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.BothE().OtherV().Has("age",
 P.Lt(30))).Times(2)}}, 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.Both().Limit<object>(1)).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.Both().Limit<object>(1)).Times(2)}},
 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Order().Repeat(__.Both().Order().Aggregate("x")).Times(2).Limit<object>(5)}},
 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Order().Repeat(__.Both().Order().Aggregate("x")).Times(2).Limit<object>(5)}},
 
+               
{"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new 
RepeatUnrollStrategy()).V().Repeat(__.Both().Sample(1)).Times(2)}}, 
+               
{"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(RepeatUnrollStrategy)).V().Repeat(__.Both().Sample(1)).Times(2)}},
 
                
{"g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXid_123X_propertyXname_markoX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new ReservedKeysVerificationStrategy(throwException: 
true)).AddV("person").Property("id", 123).Property("name", "marko")}}, 
                
{"g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXage_29X_propertyXname_markoX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new ReservedKeysVerificationStrategy(throwException: 
true, keys: new HashSet<string> { "age" })).AddV("person").Property("age", 
29).Property("name", "marko")}}, 
                
{"g_withoutStrategiesXReservedKeysVerificationStrategyX_addVXpersonX_propertyXid_123X_propertyXname_markoX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.WithoutStrategies(typeof(ReservedKeysVerificationStrategy)).AddV("person").Property("id",
 123).Property("name", "marko").Values<object>()}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index abe0614643..4dd6c5663f 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -552,6 +552,22 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_withoutStrategiesXReferenceElementStrategyX_V": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.ReferenceElementStrategy()).V()}}, 
     "g_withStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Out()).Times(2)}},
 
     "g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Out()).Times(2)}},
 
+    "g_withStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.In()).Times(2)}},
 
+    "g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.In()).Times(2)}},
 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Out().Has("name",
 gremlingo.TextP.NotStartingWith("z"))).Times(2)}}, 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Out().Has("name",
 gremlingo.TextP.NotStartingWith("z"))).Times(2)}}, 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.In().Has("age",
 gremlingo.P.Gt(20))).Times(2)}}, 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.In().Has("age",
 gremlingo.P.Gt(20))).Times(2)}}, 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Has("age",
 gremlingo.P.Lt(30))).Times(2)}}, 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Has("age",
 gremlingo.P.Lt(30))).Times(2)}}, 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.BothE().OtherV().Has("age",
 gremlingo.P.Lt(30))).Times(2)}}, 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.BothE().OtherV().Has("age",
 gremlingo.P.Lt(30))).Times(2)}}, 
+    "g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Limit(1)).Times(2)}},
 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Limit(1)).Times(2)}},
 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Order().Repeat(gremlingo.T__.Both().Order().Aggregate("x")).Times(2).Limit(5)}},
 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Order().Repeat(gremlingo.T__.Both().Order().Aggregate("x")).Times(2).Limit(5)}},
 
+    
"g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Sample(1)).Times(2)}},
 
+    
"g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.RepeatUnrollStrategy()).V().Repeat(gremlingo.T__.Both().Sample(1)).Times(2)}},
 
     
"g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXid_123X_propertyXname_markoX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.ReservedKeysVerificationStrategy(gremlingo.ReservedKeysVerificationStrategyConfig{ThrowException:
 true})).AddV("person").Property("id", 123).Property("name", "marko")}}, 
     
"g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXage_29X_propertyXname_markoX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.ReservedKeysVerificationStrategy(gremlingo.ReservedKeysVerificationStrategyConfig{ThrowException:
 true, Keys: gremlingo.NewSimpleSet("age")})).AddV("person").Property("age", 
29).Property("name", "marko")}}, 
     
"g_withoutStrategiesXReservedKeysVerificationStrategyX_addVXpersonX_propertyXid_123X_propertyXname_markoX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithoutStrategies(gremlingo.ReservedKeysVerificationStrategy()).AddV("person").Property("id",
 123).Property("name", "marko").Values()}}, 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 3230228b74..3dfb44225b 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -583,6 +583,22 @@ const gremlins = {
     g_withoutStrategiesXReferenceElementStrategyX_V: [function({g}) { return 
g.withoutStrategies(ReferenceElementStrategy).V() }], 
     g_withStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.out()).times(2) }], 
     g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X: 
[function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.out()).times(2) }], 
+    g_withStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.in_()).times(2) }], 
+    g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X: 
[function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.in_()).times(2) }], 
+    
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X:
 [function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.out().has("name", 
TextP.notStartingWith("z"))).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X:
 [function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.out().has("name", 
TextP.notStartingWith("z"))).times(2) }], 
+    
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.in_().has("age", P.gt(20))).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X:
 [function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.in_().has("age", 
P.gt(20))).times(2) }], 
+    
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.both().has("age", P.lt(30))).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X:
 [function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.both().has("age", 
P.lt(30))).times(2) }], 
+    
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X:
 [function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.bothE().otherV().has("age", 
P.lt(30))).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X:
 [function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.bothE().otherV().has("age",
 P.lt(30))).times(2) }], 
+    g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.both().limit(1)).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X: 
[function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.both().limit(1)).times(2)
 }], 
+    
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X:
 [function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().order().repeat(__.both().order().aggregate("x")).times(2).limit(5)
 }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X:
 [function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().order().repeat(__.both().order().aggregate("x")).times(2).limit(5)
 }], 
+    g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X: 
[function({g}) { return g.withStrategies(new 
RepeatUnrollStrategy()).V().repeat(__.both().sample(1)).times(2) }], 
+    
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X: 
[function({g}) { return 
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(__.both().sample(1)).times(2)
 }], 
     
g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXid_123X_propertyXname_markoX:
 [function({g}) { return g.withStrategies(new 
ReservedKeysVerificationStrategy({throwException: 
true})).addV("person").property("id", 123).property("name", "marko") }], 
     
g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXage_29X_propertyXname_markoX:
 [function({g}) { return g.withStrategies(new 
ReservedKeysVerificationStrategy({throwException: true, keys: new 
Set(["age"])})).addV("person").property("age", 29).property("name", "marko") 
}], 
     
g_withoutStrategiesXReservedKeysVerificationStrategyX_addVXpersonX_propertyXid_123X_propertyXname_markoX:
 [function({g}) { return 
g.withoutStrategies(ReservedKeysVerificationStrategy).addV("person").property("id",
 123).property("name", "marko").values() }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index f5abcb82c4..f20bf16759 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -555,6 +555,22 @@ world.gremlins = {
     'g_withoutStrategiesXReferenceElementStrategyX_V': [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ReferenceElementStrategy')]).V())],
 
     'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X': [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.out()).times(2))], 
     'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXoutX_timesX2X': 
[(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.out()).times(2))],
 
+    'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X': [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.in_()).times(2))], 
+    'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X': 
[(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.in_()).times(2))],
 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X':
 [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.out().has('name', 
TextP.not_starting_with('z'))).times(2))], 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.out().has('name',
 TextP.not_starting_with('z'))).times(2))], 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X': 
[(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.in_().has('age', 
P.gt(20))).times(2))], 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.in_().has('age',
 P.gt(20))).times(2))], 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X':
 [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.both().has('age', 
P.lt(30))).times(2))], 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.both().has('age',
 P.lt(30))).times(2))], 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X':
 [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.both_e().other_v().has('age',
 P.lt(30))).times(2))], 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.both_e().other_v().has('age',
 P.lt(30))).times(2))], 
+    'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X': 
[(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.both().limit(1)).times(2))],
 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X': 
[(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.both().limit(1)).times(2))],
 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X':
 [(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().order().repeat(__.both().order().aggregate('x')).times(2).limit(5))],
 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().order().repeat(__.both().order().aggregate('x')).times(2).limit(5))],
 
+    
'g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X': 
[(lambda 
g:g.with_strategies(RepeatUnrollStrategy()).V().repeat(__.both().sample(1)).times(2))],
 
+    
'g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X': 
[(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy')]).V().repeat(__.both().sample(1)).times(2))],
 
     
'g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXid_123X_propertyXname_markoX':
 [(lambda 
g:g.with_strategies(ReservedKeysVerificationStrategy(throw_exception=True)).add_v('person').property('id',
 123).property('name', 'marko'))], 
     
'g_withStrategiesXReservedKeysVerificationStrategyXthrowException_trueXX_addVXpersonX_propertyXage_29X_propertyXname_markoX':
 [(lambda 
g:g.with_strategies(ReservedKeysVerificationStrategy(throw_exception=True, 
keys={'age'})).add_v('person').property('age', 29).property('name', 'marko'))], 
     
'g_withoutStrategiesXReservedKeysVerificationStrategyX_addVXpersonX_propertyXid_123X_propertyXname_markoX':
 [(lambda 
g:g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReservedKeysVerificationStrategy')]).add_v('person').property('id',
 123).property('name', 'marko').values())], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/integrated/RepeatUnrollStrategy.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/integrated/RepeatUnrollStrategy.feature
index 13fd68a8c8..9ca44f3f0f 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/integrated/RepeatUnrollStrategy.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/integrated/RepeatUnrollStrategy.feature
@@ -42,3 +42,224 @@ Feature: Step - RepeatUnrollStrategy
       | result |
       | v[lop] |
       | v[ripple] |
+
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: g_withStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withStrategies(RepeatUnrollStrategy).V().repeat(in()).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXinX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withoutStrategies(RepeatUnrollStrategy).V().repeat(in()).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withStrategies(RepeatUnrollStrategy).V().repeat(out().has("name", 
notStartingWith("z"))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[lop] |
+      | v[ripple] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXout_hasXname_notStartingWithXzXXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withoutStrategies(RepeatUnrollStrategy).V().repeat(out().has("name", 
notStartingWith("z"))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[lop] |
+      | v[ripple] |
+
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withStrategies(RepeatUnrollStrategy).V().repeat(in().has("age", 
gt(20))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXin_hasXage_gtX20XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withoutStrategies(RepeatUnrollStrategy).V().repeat(in().has("age", 
gt(20))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withStrategies(RepeatUnrollStrategy).V().repeat(both().has("age", 
lt(30))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+      | v[vadas] |
+      | v[vadas] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_hasXage_ltX30XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().has("age", 
lt(30))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+      | v[vadas] |
+      | v[vadas] |
+
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withStrategies(RepeatUnrollStrategy).V().repeat(bothE().otherV().has("age", 
lt(30))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+      | v[vadas] |
+      | v[vadas] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXbothE_otherV_hasXage_ltX30XXX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(bothE().otherV().has("age",
 lt(30))).times(2)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+      | v[vadas] |
+      | v[vadas] |
+    
+  # this traversal is not expected to be unrolled by the strategy but should 
have consistent semantics compared to traversal without the strategy applied
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withStrategies(RepeatUnrollStrategy).V().repeat(both().limit(1)).times(2)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_limitX1XX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().limit(1)).times(2)
+      """
+    When iterated to list
+    Then the result should be empty
+    
+  # this traversal is not expected to be unrolled by the strategy but should 
have consistent semantics compared to traversal without the strategy applied
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withStrategies(RepeatUnrollStrategy).V().order().repeat(both().order().aggregate('x')).times(2).limit(5)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+      | v[marko] |
+      | v[lop] |
+      | v[josh] |
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_aggregateXxXX_timesX2X_limitX5X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withoutStrategies(RepeatUnrollStrategy).V().order().repeat(both().order().aggregate('x')).times(2).limit(5)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+      | v[marko] |
+      | v[lop] |
+      | v[josh] |
+    
+  # this traversal is not expected to be unrolled by the strategy but should 
have consistent semantics compared to traversal without the strategy applied
+  @WithRepeatUnrollStrategy
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withStrategies(RepeatUnrollStrategy).V().repeat(both().sample(1)).times(2)
+      """
+    When iterated to list
+    Then the result should have a count of 6
+
+  @GraphComputerVerificationStrategyNotSupported
+  Scenario: 
g_withoutStrategiesXRepeatUnrollStrategyX_V_repeatXboth_sampleX1XX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      
g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().sample(1)).times(2)
+      """
+    When iterated to list
+    Then the result should have a count of 6

Reply via email to