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

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


The following commit(s) were added to refs/heads/3.7-dev by this push:
     new d05ddc04a1 TINKERPOP-3283: loops() quietly overflows (#3688)
d05ddc04a1 is described below

commit d05ddc04a1bfcf902094fb9862bf8b707ee6d674
Author: Iryna-Kahamlyk <[email protected]>
AuthorDate: Mon Oct 5 13:40:13 2026 -0700

    TINKERPOP-3283: loops() quietly overflows (#3688)
    
    Fixed `loops()` silently overflowing its internal counter and wrapping to a 
negative count; the counter now uses `int` instead of `short` globally and 
throws an `IllegalStateException` if Integer.MAX_VALUE iterations is ever 
exceeded.
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/dev/provider/gremlin-semantics.asciidoc   |  4 ++
 docs/src/reference/the-traversal.asciidoc          |  3 +
 .../traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java   |  2 +-
 .../traverser/B_LP_NL_O_S_SE_SL_Traverser.java     |  2 +-
 .../traverser/B_NL_O_S_SE_SL_Traverser.java        |  2 +-
 .../traversal/traverser/B_O_S_SE_SL_Traverser.java |  4 +-
 .../traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java  |  2 +-
 .../traverser/LP_NL_O_OB_S_SE_SL_Traverser.java    |  2 +-
 .../traverser/NL_O_OB_S_SE_SL_Traverser.java       |  2 +-
 .../traverser/O_OB_S_SE_SL_Traverser.java          |  4 +-
 .../traversal/traverser/util/LabelledCounter.java  | 10 +--
 .../traverser/LoopCounterOverflowTest.java         | 74 ++++++++++++++++++++++
 .../traverser/util/LabelledCounterTest.java        | 46 ++++++++++++++
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  1 +
 gremlin-go/driver/cucumber/gremlin.go              |  1 +
 .../gremlin-javascript/test/cucumber/gremlin.js    |  1 +
 .../src/main/python/tests/feature/gremlin.py       |  1 +
 .../gremlin/test/features/branch/Repeat.feature    | 12 ++++
 19 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index b4e56b9526..41168ce7d7 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 [[release-3-7-8]]
 === TinkerPop 3.7.8 (Release Date: NOT OFFICIALLY RELEASED YET)
 
+* Fixed `loops()` silently overflowing its internal counter and wrapping to a 
negative count; the counter now uses `int` instead of `short` and throws an 
`IllegalStateException` if Integer.MAX_VALUE iterations is ever exceeded.
 * Fixed `gremlin-python` GraphBinary serialization of `int` values outside the 
Java `int` range, which raised a `struct.error` rather than writing a `Long`.
 
 [[release-3-7-7]]
diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc 
b/docs/src/dev/provider/gremlin-semantics.asciidoc
index 215a069d9c..0ce7e138b0 100644
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@ -1466,6 +1466,8 @@ predicates are evaluated before the first iteration (pre) 
or after each iteratio
 after the body finishes), not before. Therefore, `loops()` reflects the number 
of completed iterations.
   - `loops()` without arguments returns the counter for the closest 
(innermost) `repeat()`. `loops("name")` returns the
 counter for the named loop.
+  - The loop counter is bounded to `Integer.MAX_VALUE` (2,147,483,647) 
iterations. Exceeding this bound raises an error
+(see Exceptions).
 - Re-queuing for the next iteration:
   - After each iteration, if `until` is not satisfied at the post-check, the 
traverser is sent back into the loop body
 for another iteration. If it is satisfied, the traverser exits the loop and 
proceeds downstream.
@@ -1485,6 +1487,8 @@ message containing: `The repeat()-traversal was not 
defined`.
 
 * Using `emit()`, `until()`, or `times()` without a matching `repeat()` will 
raise an `IllegalStateException` at runtime
   when the step is initialized during iteration with the message containing: 
`The repeat()-traversal was not defined`.
+* Incrementing a loop counter past `Integer.MAX_VALUE` (2,147,483,647) will 
raise an `IllegalStateException` with a
+  message containing: `has exceeded the maximum supported value`.
 
 See: 
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java[source],
 link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference],
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index 2749f76483..8b84fca91d 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2521,6 +2521,9 @@ The `loops()`-step (*map*) extracts the number of times 
the `Traverser` has gone
 g.V().emit(__.has("name", 
"marko").or().loops().is(2)).repeat(__.out()).values("name")
 ----
 
+WARNING: The loop counter is limited to 2,147,483,647 iterations. A `repeat()` 
construct that loops
+beyond that limit throws an `IllegalStateException`.
+
 *Additional References*
 
 
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#loops()++[`loops()`],
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
index d8e24d2b3d..5f2e4d59f1 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
@@ -60,7 +60,7 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends 
B_LP_O_P_S_SE_SL_Traverser
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
index 07c2b84598..0e3e62a077 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
@@ -60,7 +60,7 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends 
B_LP_O_S_SE_SL_Traverser<T>
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
index 4268526199..c37b568daa 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
@@ -59,7 +59,7 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends 
B_O_S_SE_SL_Traverser<T> {
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
index 2f78668a1c..10ec80ef7a 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
@@ -32,7 +32,7 @@ import java.util.Set;
 public class B_O_S_SE_SL_Traverser<T> extends B_O_Traverser<T> {
 
     protected Object sack = null;
-    protected short loops = 0;  // an optimization hack to use a short 
internally to save bits :)
+    protected int loops = 0;
     protected String loopName = null;
     protected transient TraversalSideEffects sideEffects;
 
@@ -85,6 +85,8 @@ public class B_O_S_SE_SL_Traverser<T> extends 
B_O_Traverser<T> {
 
     @Override
     public void incrLoops() {
+        if (this.loops == Integer.MAX_VALUE)
+            throw new IllegalStateException("Loop counter has exceeded the 
maximum supported value of " + Integer.MAX_VALUE);
         this.loops++;
     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
index aae7689083..7013cc3e83 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
@@ -61,7 +61,7 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends 
LP_O_OB_P_S_SE_SL_Travers
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
index b34493133e..e93840bb2b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
@@ -66,7 +66,7 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends 
LP_O_OB_S_SE_SL_Traverser<T
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
index 2fc4240a35..9564c81a57 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
@@ -61,7 +61,7 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends 
O_OB_S_SE_SL_Traverser<T> {
     @Override
     public void initialiseLoops(final String stepLabel, final String loopName) 
{
         if (this.nestedLoops.empty() || 
!this.nestedLoops.peek().hasLabel(stepLabel)) {
-            final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 
0);
+            final LabelledCounter lc = new LabelledCounter(stepLabel, 0);
             this.nestedLoops.push(lc);
             if (loopName != null)
                 this.loopNames.put(loopName, lc);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
index c748a91d2b..a6ff843d55 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
@@ -33,7 +33,7 @@ import java.util.Set;
 public class O_OB_S_SE_SL_Traverser<T> extends O_Traverser<T> {
 
     protected Object sack = null;
-    protected short loops = 0;  // an optimization hack to use a short 
internally to save bits :)
+    protected int loops = 0;
     protected String loopName = null;
     protected transient TraversalSideEffects sideEffects;
     protected String future = HALT;
@@ -98,6 +98,8 @@ public class O_OB_S_SE_SL_Traverser<T> extends O_Traverser<T> 
{
 
     @Override
     public void incrLoops() {
+        if (this.loops == Integer.MAX_VALUE)
+            throw new IllegalStateException("Loop counter has exceeded the 
maximum supported value of " + Integer.MAX_VALUE);
         this.loops++;
     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
index b1a1d9779d..0b7b524de7 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
@@ -27,13 +27,13 @@ import java.io.Serializable;
 public class LabelledCounter implements Serializable, Cloneable {
 
     private final String label;
-    private short count = 0;
+    private int count = 0;
 
     protected LabelledCounter() {
         label = "";
     }
 
-    public LabelledCounter(final String label, final short initialCount) {
+    public LabelledCounter(final String label, final int initialCount) {
         if (label == null) {
             throw new NullPointerException("Label is null");
         }
@@ -50,6 +50,8 @@ public class LabelledCounter implements Serializable, 
Cloneable {
     }
 
     public void increment() {
+        if (this.count == Integer.MAX_VALUE)
+            throw new IllegalStateException("Loop counter for label '" + 
this.label + "' has exceeded the maximum supported value of " + 
Integer.MAX_VALUE);
         this.count++;
     }
 
@@ -60,7 +62,7 @@ public class LabelledCounter implements Serializable, 
Cloneable {
 
     @Override
     public String toString(){
-        return "Step Label: " + this.label + " Counter: " + 
Short.toString(this.count);
+        return "Step Label: " + this.label + " Counter: " + 
Integer.toString(this.count);
     }
 
     @Override
@@ -77,7 +79,7 @@ public class LabelledCounter implements Serializable, 
Cloneable {
     @Override
     public int hashCode() {
         int result = label != null ? label.hashCode() : 0;
-        result = 31 * result + (int) count;
+        result = 31 * result + count;
         return result;
     }
 }
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LoopCounterOverflowTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LoopCounterOverflowTest.java
new file mode 100644
index 0000000000..9df7a4943e
--- /dev/null
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LoopCounterOverflowTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.traverser;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class LoopCounterOverflowTest {
+
+    // Overflow is seeded directly at Integer.MAX_VALUE rather than reached by 
looping incrLoops()
+    // billions of times, which would be impractical for a unit test.
+
+    @Test
+    public void shouldThrowOnSingleLoopOverflow() {
+        final GraphTraversalSource g = EmptyGraph.instance().traversal();
+        final Traversal.Admin traversal = 
g.withBulk(false).V().repeat(__.out()).times(10).asAdmin();
+        traversal.applyStrategies();
+        final Traverser.Admin<?> traverser = 
traversal.getTraverserGenerator().generate(new Object(), 
traversal.getStartStep(), 1L);
+        assertEquals(O_OB_S_SE_SL_Traverser.class, traverser.getClass());
+
+        ((O_OB_S_SE_SL_Traverser<?>) traverser).loops = Integer.MAX_VALUE;
+        assertEquals(Integer.MAX_VALUE, traverser.loops());
+
+        try {
+            traverser.incrLoops();
+            fail("Should have thrown an IllegalStateException when the loop 
counter overflows an int");
+        } catch (IllegalStateException ise) {
+            assertEquals(Integer.MAX_VALUE, traverser.loops());
+        }
+    }
+
+    @Test
+    public void shouldThrowOnNestedLoopOverflow() {
+        final GraphTraversalSource g = EmptyGraph.instance().traversal();
+        final Traversal.Admin traversal = 
g.withBulk(false).V().repeat(__.repeat(__.out())).times(10).asAdmin();
+        traversal.applyStrategies();
+        final Traverser.Admin<?> traverser = 
traversal.getTraverserGenerator().generate(new Object(), 
traversal.getStartStep(), 1L);
+        assertEquals(NL_O_OB_S_SE_SL_Traverser.class, traverser.getClass());
+
+        ((NL_O_OB_S_SE_SL_Traverser<?>) traverser).nestedLoops.push(new 
LabelledCounter("repeat", Integer.MAX_VALUE));
+        assertEquals(Integer.MAX_VALUE, traverser.loops());
+
+        try {
+            traverser.incrLoops();
+            fail("Should have thrown an IllegalStateException when the loop 
counter overflows an int");
+        } catch (IllegalStateException ise) {
+            assertEquals(Integer.MAX_VALUE, traverser.loops());
+        }
+    }
+}
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounterTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounterTest.java
new file mode 100644
index 0000000000..d567b07bef
--- /dev/null
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounterTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.traverser.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class LabelledCounterTest {
+
+    @Test
+    public void shouldIncrementCount() {
+        final LabelledCounter lc = new LabelledCounter("a", 0);
+        lc.increment();
+        lc.increment();
+        assertEquals(2, lc.count());
+    }
+
+    @Test
+    public void shouldThrowOnOverflow() {
+        final LabelledCounter lc = new LabelledCounter("a", Integer.MAX_VALUE);
+        try {
+            lc.increment();
+            fail("Should have thrown an IllegalStateException when the loop 
counter overflows an int");
+        } catch (IllegalStateException ise) {
+            assertEquals(Integer.MAX_VALUE, lc.count());
+        }
+    }
+}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index fe51031bab..6a85f9ebb7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -119,6 +119,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_emit", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Emit()}}, 
                {"g_V_untilXidentityX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().Until(__.Identity())}}, 
                {"g_V_timesX5X", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Times(5)}}, 
+               {"g_VX1X_repeatXloopsX_timesX100000X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V(p["vid1"]).Repeat(__.Loops()).Times(100000)}}, 
                
{"g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX1X_name", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().Has("person","name","marko").Repeat(__.Out("created")).Times(1).Values<object>("name")}},
 
                
{"g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX0X_name", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().Has("person","name","marko").Repeat(__.Out("created")).Times(0).Values<object>("name")}},
 
                
{"g_V_haxXperson_name_markoX_timesX1X_repeatXoutXcreatedXX_name", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().Has("person","name","marko").Times(1).Repeat(__.Out("created")).Values<object>("name")}},
 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index d1de80cda4..321b7fc946 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -90,6 +90,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_V_emit": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Emit()}}, 
     "g_V_untilXidentityX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Until(gremlingo.T__.Identity())}}, 
     "g_V_timesX5X": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Times(5)}}, 
+    "g_VX1X_repeatXloopsX_timesX100000X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).Repeat(gremlingo.T__.Loops()).Times(100000)}}, 
     "g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX1X_name": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Has("person", "name", 
"marko").Repeat(gremlingo.T__.Out("created")).Times(1).Values("name")}}, 
     "g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX0X_name": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Has("person", "name", 
"marko").Repeat(gremlingo.T__.Out("created")).Times(0).Values("name")}}, 
     "g_V_haxXperson_name_markoX_timesX1X_repeatXoutXcreatedXX_name": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Has("person", "name", 
"marko").Times(1).Repeat(gremlingo.T__.Out("created")).Values("name")}}, 
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 a83296fcd6..4749161753 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
@@ -110,6 +110,7 @@ const gremlins = {
     g_V_emit: [function({g}) { return g.V().emit() }], 
     g_V_untilXidentityX: [function({g}) { return g.V().until(__.identity()) 
}], 
     g_V_timesX5X: [function({g}) { return g.V().times(5) }], 
+    g_VX1X_repeatXloopsX_timesX100000X: [function({g, vid1}) { return 
g.V(vid1).repeat(__.loops()).times(100000) }], 
     g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX1X_name: 
[function({g}) { return 
g.V().has("person","name","marko").repeat(__.out("created")).times(1).values("name")
 }], 
     g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX0X_name: 
[function({g}) { return 
g.V().has("person","name","marko").repeat(__.out("created")).times(0).values("name")
 }], 
     g_V_haxXperson_name_markoX_timesX1X_repeatXoutXcreatedXX_name: 
[function({g}) { return 
g.V().has("person","name","marko").times(1).repeat(__.out("created")).values("name")
 }], 
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py 
b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 3580de30dd..530b3915b7 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -92,6 +92,7 @@ world.gremlins = {
     'g_V_emit': [(lambda g:g.V().emit())], 
     'g_V_untilXidentityX': [(lambda g:g.V().until(__.identity()))], 
     'g_V_timesX5X': [(lambda g:g.V().times(5))], 
+    'g_VX1X_repeatXloopsX_timesX100000X': [(lambda g, 
vid1=None:g.V(vid1).repeat(__.loops()).times(100000))], 
     'g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX1X_name': [(lambda 
g:g.V().has('person','name','marko').repeat(__.out('created')).times(1).name)], 
     'g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX0X_name': [(lambda 
g:g.V().has('person','name','marko').repeat(__.out('created')).times(0).name)], 
     'g_V_haxXperson_name_markoX_timesX1X_repeatXoutXcreatedXX_name': [(lambda 
g:g.V().has('person','name','marko').times(1).repeat(__.out('created')).name)], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
index 5c3d3e5e68..3e635f0fcf 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature
@@ -399,6 +399,18 @@ Feature: Step - repeat()
     When iterated to list
     Then the traversal will raise an error with message containing text of 
"The repeat()-traversal was not defined"
 
+  Scenario: g_VX1X_repeatXloopsX_timesX100000X
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).repeat(__.loops()).times(100000)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[99999].i |
+
   Scenario: g_V_haxXperson_name_markoX_repeatXoutXcreatedXX_timesX1X_name
     Given the modern graph
     And the traversal of

Reply via email to