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

xiazcy pushed a commit to branch type-enum-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 7ef100a5630103fe101c51e2b0c3da4e7cf95b63
Author: xiazcy <[email protected]>
AuthorDate: Thu Jul 17 10:35:17 2025 -0700

    added comprehensive unit tests & updated asNumber() implementation
---
 docs/src/reference/the-traversal.asciidoc          |   6 +-
 .../tinkerpop/gremlin/process/traversal/N.java     |  29 +-
 .../traversal/dsl/graph/GraphTraversal.java        |   8 +-
 .../process/traversal/step/map/AsNumberStep.java   | 105 +-------
 .../gremlin/structure/io/gryo/GryoVersion.java     |  17 +-
 .../tinkerpop/gremlin/util/NumberHelper.java       |  75 ++++++
 .../traversal/step/map/AsNumberStepTest.java       | 291 ++++++++++++++++++++-
 .../tinkerpop/gremlin/util/NumberHelperTest.java   |  75 ++++++
 .../gremlin/test/features/map/AsNumber.feature     |   2 +-
 9 files changed, 476 insertions(+), 132 deletions(-)

diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index e39425881c..39dd9f9c39 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -836,13 +836,13 @@ The `asNumber()`-step (*map*) converts the incoming 
traverser to the nearest par
 
 Numerical input will pass through unless a type is specified by the number 
token, with the exception that any float number will be converted into double. 
`ArithmeticException` will be thrown for any overflow during narrowing of types.
 
-String input will be parsed. By default, the smalled unit of number to be 
parsed into is `int` if no number token is provided. `NumberFormatException` 
will be thrown for any unparsable strings.
+String inputs are parsed into numeric values. By default, the value will be 
parsed as an integer if it represents a whole number, or as a double if it 
contains a decimal point. A `NumberFormatException` will be thrown if the 
string cannot be parsed into a valid number format.
 
 All other input types will result in `IllegalArgumentException`.
 
 [gremlin-groovy,modern]
 ----
-g.inject(1).asNumber() <1>
+g.inject(1234).asNumber() <1>
 g.inject(1.76).asNumber() <2>
 g.inject(1.76).asNumber(N.nint) <3>
 g.inject("1b").asNumber() <4>
@@ -851,7 +851,7 @@ g.inject(33550336).asNumber(N.nbyte) <5>
 
 <1> An int will be passed through.
 <2> A double will be passed through.
-<3> A double is converted into an in.
+<3> A double is converted into an int.
 <4> String containing any character other than numerical ones will result in 
`NumberFormatException`.
 <5> Narrowing of int to byte that overflows will throw `ArithmeticException`.
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java
index 67eda53a7d..4a8d56b48b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java
@@ -20,26 +20,33 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
  * Tokens that are used to denote different units of number.
  * Used with {@link AsNumberStep} step.
  */
 public enum N {
-    nbyte("Byte"),
-    nshort("Short"),
-    nint("Integer"),
-    nlong("Long"),
-    nfloat("Float"),
-    ndouble("Double"),
-    nbigInt("BigInt"),
-    nbigDecimal("BigDecimal"),;
+    nbyte(Byte.class),
+    nshort(Short.class),
+    nint(Integer.class),
+    nlong(Long.class),
+    nfloat(Float.class),
+    ndouble(Double.class),
+    nbigInt(BigInteger.class),
+    nbigDecimal(BigDecimal.class),;
+
+    private final Class<?> type;
 
-    private final String typeName;
+    N(Class<?> type) {this.type = type;}
 
-    N(String name) {typeName = name;}
+    public Class<?> getType() {
+        return this.type;
+    }
 
     @Override
     public String toString() {
-        return typeName;
+        return this.type.getSimpleName();
     }
 }
\ No newline at end of file
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 40cda64a36..aa3c2cfbc5 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -1918,11 +1918,11 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
     }
 
     /**
-     * Parse value of the incoming traverser as an ISO-8601 {@link Number}.
+     * Parse value of the incoming traverser as a {@link Number}.
      *
      * @return the traversal with an appended {@link AsNumberStep}.
      * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#AsNumberStep-step";
 target="_blank">Reference Documentation - AsNumberStep Step</a>
-     * @since 3.7.1
+     * @since 3.8.0
      */
     public default GraphTraversal<S, Number> asNumber() {
         this.asAdmin().getBytecode().addStep(Symbols.asNumber);
@@ -1930,11 +1930,11 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
     }
 
     /**
-     * Parse value of the incoming traverser as an ISO-8601 {@link Number}.
+     * Parse value of the incoming traverser as a {@link Number}.
      *
      * @return the traversal with an appended {@link AsNumberStep}.
      * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#AsNumberStep-step";
 target="_blank">Reference Documentation - AsNumberStep Step</a>
-     * @since 3.7.1
+     * @since 3.8.0
      */
     public default GraphTraversal<S, Number> asNumber(final N numberToken) {
         this.asAdmin().getBytecode().addStep(Symbols.asNumber, numberToken);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
index 1fb093be11..59e88ef604 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
@@ -26,19 +26,13 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequire
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.NumberHelper;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Calendar;
 import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 
 /**
  * Reference implementation for number parsing step.
  */
-public final class AsNumberStep<S> extends ScalarMapStep<S, Number> {
+public class AsNumberStep<S> extends ScalarMapStep<S, Number> {
 
     private N numberToken;
 
@@ -58,10 +52,10 @@ public final class AsNumberStep<S> extends ScalarMapStep<S, 
Number> {
         if (object instanceof String) {
             String numberText = (String) object;
             Number number = parseNumber(numberText);
-            return numberToken == null ? autoNumber(number) : 
castNumber(number, numberToken);
+            return numberToken == null ? number : castNumber(number, 
numberToken);
         } else if (object instanceof Number) {
             Number number = (Number) object;
-            return numberToken == null ? autoNumber(number) : 
castNumber(number, numberToken);
+            return numberToken == null ? number : castNumber(number, 
numberToken);
         }
         throw new IllegalArgumentException(String.format("Can't parse type %s 
as number.", object == null ? "null" : object.getClass().getSimpleName()));
     }
@@ -96,97 +90,14 @@ public final class AsNumberStep<S> extends ScalarMapStep<S, 
Number> {
     }
 
     public static Number parseNumber(final String value) {
-        try {
-            boolean isFloatingPoint = value.contains(".") || 
value.contains("e") || value.contains("E");
-            if (isFloatingPoint) {
-                BigDecimal result = new BigDecimal(value.trim());
-                if (BigDecimal.valueOf(result.doubleValue()).compareTo(result) 
== 0) {
-                    return result.doubleValue();
-                }
-                return result;
-            }
-            BigInteger result = new BigInteger(value.trim());
-            if (result.bitLength() <= 31) { // default to int if not 
specified, smaller sizes need to be intentionally set
-                return result.intValue();
-            } else if (result.bitLength() <= 63) {
-                return result.longValue();
-            }
-            return result;
-        } catch (NumberFormatException nfe) {
-            throw new NumberFormatException(String.format("Can't parse string 
'%s' as number.", value));
+        if (NumberUtils.isCreatable(value.trim())) {
+            return NumberUtils.createNumber(value.trim());
         }
+        throw new NumberFormatException(String.format("Can't parse string '%s' 
as number.", value));
     }
 
-    private static Number autoNumber(Number number) {
-        final Class<? extends Number> clazz = number.getClass();
-        if (clazz.equals(Float.class)) {
-            return castNumber(number, N.ndouble);
-        }
-        return number;
-    }
-
-    private static Number castNumber(Number number, N numberToken) {
-        int sourceBits = getNumberBitsBasedOnValue(number);
-        int targetBits = getNumberTokenBits(numberToken);
-        if (sourceBits > targetBits) {
-            throw new ArithmeticException(String.format("Can't convert number 
of type %s to %s due to overflow.",
-                    number.getClass().getSimpleName(), 
numberToken.toString()));
-        }
-        if (numberToken == N.nbyte) {
-            return number.byteValue();
-        } else if (numberToken == N.nshort) {
-            return number.shortValue();
-        } else if (numberToken == N.nint) {
-            return number.intValue();
-        } else if (numberToken == N.nlong) {
-            return number.longValue();
-        } else if (numberToken == N.nfloat) {
-            return number.floatValue();
-        } else if (numberToken == N.ndouble) {
-            return number.doubleValue();
-        } else if (numberToken == N.nbigInt) {
-            return BigInteger.valueOf(number.longValue());
-        } else if (numberToken == N.nbigDecimal) {
-            return BigDecimal.valueOf(number.doubleValue());
-        }
-        return number;
+    private static Number castNumber(final Number number, final N numberToken) 
{
+        return NumberHelper.castTo(number, numberToken);
     }
 
-    private static int getNumberBitsBasedOnValue(Number number) {
-        final Class<? extends Number> clazz = number.getClass();
-        if (clazz.equals(BigInteger.class)) {
-            return 128;
-        } else if (clazz.equals(BigDecimal.class)) {
-            return 128;
-        }
-        boolean floatingPoint = (clazz.equals(Float.class) || 
clazz.equals(Double.class));
-        if (!floatingPoint && (number.longValue() >= Byte.MIN_VALUE) && 
(number.longValue() <= Byte.MAX_VALUE)) {
-            return 8;
-        } else if (!floatingPoint && (number.longValue() >= Short.MIN_VALUE) 
&& (number.longValue() <= Short.MAX_VALUE)) {
-            return 16;
-        } else if (!floatingPoint && (number.longValue() >= Integer.MIN_VALUE) 
&& (number.longValue() <= Integer.MAX_VALUE)) {
-            return 32;
-        } else if (floatingPoint && (number.doubleValue() >= Float.MIN_VALUE) 
&& (number.doubleValue() <= Float.MAX_VALUE)) {
-            return 32;
-        } else {
-            return 64;
-        }
-    }
-
-    private static int getNumberTokenBits(N numberToken) {
-        if (numberToken == N.nbyte) {
-            return 8;
-        } else if (numberToken == N.nshort) {
-            return 16;
-        } else if (numberToken == N.nint) {
-            return 32;
-        } else if (numberToken == N.nlong) {
-            return 64;
-        } else if (numberToken == N.nfloat) {
-            return 32;
-        } else if (numberToken == N.ndouble) {
-            return 64;
-        }
-        return 128;
-    }
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index 65b0f7164c..d3e3a79d29 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -25,20 +25,7 @@ import 
org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimiza
 import org.apache.tinkerpop.gremlin.process.computer.util.ComputerGraph;
 import org.apache.tinkerpop.gremlin.process.computer.util.MapMemory;
 import 
org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
-import org.apache.tinkerpop.gremlin.process.traversal.Contains;
-import org.apache.tinkerpop.gremlin.process.traversal.DT;
-import org.apache.tinkerpop.gremlin.process.traversal.Merge;
-import org.apache.tinkerpop.gremlin.process.traversal.Operator;
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
-import org.apache.tinkerpop.gremlin.process.traversal.Pick;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
-import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
-import org.apache.tinkerpop.gremlin.process.traversal.Text;
-import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+import org.apache.tinkerpop.gremlin.process.traversal.*;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -551,7 +538,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(Pick.class, 137));
             add(GryoTypeReg.of(DT.class, 198));
             add(GryoTypeReg.of(Merge.class, 196));
-            add(GryoTypeReg.of(DT.class, 199));
+            add(GryoTypeReg.of(N.class, 200));
             add(GryoTypeReg.of(HashSetSupplier.class, 136, new 
UtilSerializers.HashSetSupplierSerializer()));
             add(GryoTypeReg.of(MultiComparator.class, 165));
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java
index 78df426e9f..137156fbcc 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.util;
 
+import org.apache.tinkerpop.gremlin.process.traversal.N;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.MathContext;
@@ -721,6 +723,79 @@ public final class NumberHelper {
         return a;
     }
 
+    /**
+     * Casts the given number to the specified numeric type if it can fit into 
it.
+     * Otherwise, throw.
+     *
+     * @param a the number to be cast
+     * @param numberToken the number token denoting the desired type to cast
+     * @return the number cast to the specified type
+     * @throws IllegalArgumentException if the specified numeric type is 
unsupported
+     * @throws ArithmeticException if the number overflows
+     */
+    public static Number castTo(final Number a, final N numberToken) {
+        Class<?> clazz = numberToken.getType();
+        if (a.getClass().equals(clazz)) {
+            return a;
+        } else if (clazz.equals(Integer.class)) {
+            Long val = getLong(a, numberToken);
+            if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) {
+                return a.intValue();
+            }
+        } else if (clazz.equals(Long.class)) {
+            return getLong(a, numberToken);
+        } else if (clazz.equals(Float.class)) {
+            // BigDecimal to double will overflow into Infinity, we want to 
throw instead of passing through
+            if (!a.getClass().equals(BigDecimal.class) &&
+                    (Double.isInfinite(a.doubleValue()) || 
Double.isNaN(a.doubleValue())))  {
+                return a.floatValue();
+            }
+            if (a.doubleValue() >= -Float.MAX_VALUE && a.doubleValue() <= 
Float.MAX_VALUE) {
+                return a.floatValue();
+            }
+        } else if (clazz.equals(Double.class)) {
+            // BigDecimal to double will overflow into Infinity,  we want to 
throw instead of passing through
+            if (!a.getClass().equals(BigDecimal.class) &&
+                    (Double.isInfinite(a.doubleValue()) || 
Double.isNaN(a.doubleValue()))) {
+                return a.doubleValue();
+            }
+            if (!Double.isInfinite(a.doubleValue())) {
+                // float losses precision, use string intermediate
+                return a.getClass().equals(Float.class) ? 
Double.parseDouble(a.toString()) : a.doubleValue();
+            }
+        } else if (clazz.equals(Byte.class)) {
+            Long val = getLong(a, numberToken);
+            if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
+                return a.byteValue();
+            }
+        } else if (clazz.equals(Short.class)) {
+            Long val = getLong(a, numberToken);
+            if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
+                return a.shortValue();
+            }
+        } else if (clazz.equals(BigInteger.class)) {
+            return NumberHelper.bigIntegerValue(a);
+        } else if (clazz.equals(BigDecimal.class)) {
+            // float losses precision, use string intermediate
+            return a.getClass().equals(Float.class) ? new 
BigDecimal(a.toString()) : NumberHelper.bigDecimalValue(a);
+        } else {
+            throw new IllegalArgumentException("Unsupported number type token: 
" + numberToken);
+        }
+
+        throw new ArithmeticException(String.format("Can't convert number of 
type %s to %s due to overflow.",
+                a.getClass().getSimpleName(), numberToken));
+    }
+
+    private static Long getLong(Number num, N numberToken) {
+        try {
+            return num.getClass().equals(BigInteger.class) ? ((BigInteger) 
num).longValueExact() : num.longValue();
+        } catch (ArithmeticException ae) {
+            throw new ArithmeticException(String.format("Can't convert number 
of type %s to %s due to overflow.",
+                    num.getClass().getSimpleName(), numberToken));
+        }
+
+    }
+
     private static NumberHelper getHelper(final Class<? extends Number> clazz) 
{
         if (clazz.equals(Byte.class)) {
             return BYTE_NUMBER_HELPER;
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
index 396d4bd8e4..eb1f9547d8 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
@@ -24,12 +24,13 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
 import org.junit.Test;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
 public class AsNumberStepTest extends StepTest {
@@ -46,9 +47,18 @@ public class AsNumberStepTest extends StepTest {
         assertEquals(1, __.__(1.8).asNumber(N.nint).next());
         assertEquals(1, __.__(1L).asNumber(N.nint).next());
         assertEquals(1L, __.__(1L).asNumber().next());
+        assertEquals(3.14f, __.__(3.14).asNumber(N.nfloat).next());
+        assertEquals(3.14, __.__(3.14f).asNumber(N.ndouble).next());
         assertEquals(1, __.__("1").asNumber(N.nint).next());
         assertEquals(1, __.__("1").asNumber().next());
         assertEquals((byte) 1, __.__("1").asNumber(N.nbyte).next());
+        assertEquals((short) 1, __.__("1").asNumber(N.nshort).next());
+        assertEquals(1L, __.__("1").asNumber(N.nlong).next());
+        assertEquals(3.14, __.__("3.14").asNumber(N.ndouble).next()); //float 
to double
+        // NumberUtils allows additional string processing
+        assertEquals(123.0f, __.__("123.").asNumber().next());
+        assertEquals(291, __.__("0x123").asNumber().next());
+        assertEquals(83, __.__("0123").asNumber().next());
     }
 
     @Test(expected = NumberFormatException.class)
@@ -81,4 +91,283 @@ public class AsNumberStepTest extends StepTest {
         __.__(128).asNumber(N.nbyte).next();
     }
 
+    @Test
+    public void testStringToByte() {
+        assertEquals((byte) 0, __.__("0").asNumber(N.nbyte).next());
+        assertEquals((byte) 127, __.__("127").asNumber(N.nbyte).next());
+        assertEquals((byte) -128, __.__("-128").asNumber(N.nbyte).next());
+        assertEquals((byte) 42, __.__("42").asNumber(N.nbyte).next());
+        assertEquals((byte) -42, __.__("-42").asNumber(N.nbyte).next());
+        assertEquals((byte) 1, __.__("1").asNumber(N.nbyte).next());
+    }
+
+    @Test
+    public void testStringToShort() {
+        assertEquals((short) 0, __.__("0").asNumber(N.nshort).next());
+        assertEquals((short) 32767, __.__("32767").asNumber(N.nshort).next());
+        assertEquals((short) -32768, 
__.__("-32768").asNumber(N.nshort).next());
+        assertEquals((short) 1000, __.__("1000").asNumber(N.nshort).next());
+        assertEquals((short) -1000, __.__("-1000").asNumber(N.nshort).next());
+        assertEquals((short) 255, __.__("255").asNumber(N.nshort).next());
+    }
+
+    @Test
+    public void testStringToInt() {
+        assertEquals(0, __.__("0").asNumber(N.nint).next());
+        assertEquals(2147483647, __.__("2147483647").asNumber(N.nint).next());
+        assertEquals(-2147483648, 
__.__("-2147483648").asNumber(N.nint).next());
+        assertEquals(123456, __.__("123456").asNumber(N.nint).next());
+        assertEquals(-123456, __.__("-123456").asNumber(N.nint).next());
+        assertEquals(65536, __.__("65536").asNumber(N.nint).next());
+    }
+
+    @Test
+    public void testStringToLong() {
+        assertEquals(0L, __.__("0").asNumber(N.nlong).next());
+        assertEquals(9223372036854775807L, 
__.__("9223372036854775807").asNumber(N.nlong).next());
+        assertEquals(-9223372036854775808L, 
__.__("-9223372036854775808").asNumber(N.nlong).next());
+        assertEquals(123456789L, __.__("123456789").asNumber(N.nlong).next());
+        assertEquals(-123456789L, 
__.__("-123456789").asNumber(N.nlong).next());
+        assertEquals(4294967296L, 
__.__("4294967296").asNumber(N.nlong).next());
+    }
+
+    @Test
+    public void testStringToFloat() {
+        assertEquals(0.0f, __.__("0.0").asNumber(N.nfloat).next());
+        assertEquals(3.14f, __.__("3.14").asNumber(N.nfloat).next());
+        assertEquals(-3.14f, __.__("-3.14").asNumber(N.nfloat).next());
+        assertEquals(1.23e10f, __.__("1.23e10").asNumber(N.nfloat).next());
+        assertEquals(-1.23e-10f, __.__("-1.23e-10").asNumber(N.nfloat).next());
+        assertEquals(Float.MAX_VALUE, 
__.__("3.4028235E38").asNumber(N.nfloat).next());
+        assertEquals(Float.MIN_VALUE, 
__.__("1.4E-45").asNumber(N.nfloat).next());
+    }
+
+    @Test
+    public void testStringToDouble() {
+        assertEquals(0.0, __.__("0.0").asNumber(N.ndouble).next());
+        assertEquals(3.141592653589793, 
__.__("3.141592653589793").asNumber(N.ndouble).next());
+        assertEquals(-3.141592653589793, 
__.__("-3.141592653589793").asNumber(N.ndouble).next());
+        assertEquals(1.23e100, __.__("1.23e100").asNumber(N.ndouble).next());
+        assertEquals(-1.23e-100, 
__.__("-1.23e-100").asNumber(N.ndouble).next());
+        assertEquals(Double.MAX_VALUE, 
__.__("1.7976931348623157E308").asNumber(N.ndouble).next());
+        assertEquals(Double.MIN_VALUE, 
__.__("4.9E-324").asNumber(N.ndouble).next());
+    }
+
+    @Test
+    public void testStringToBigInteger() {
+        assertEquals(new BigInteger("0"), 
__.__("0").asNumber(N.nbigInt).next());
+        assertEquals(new BigInteger("123456789012345678901234567890"),
+                
__.__("123456789012345678901234567890").asNumber(N.nbigInt).next());
+        assertEquals(new BigInteger("-123456789012345678901234567890"),
+                
__.__("-123456789012345678901234567890").asNumber(N.nbigInt).next());
+        assertEquals(new 
BigInteger("999999999999999999999999999999999999999999999999999"),
+                
__.__("999999999999999999999999999999999999999999999999999").asNumber(N.nbigInt).next());
+        assertEquals(new BigInteger("1"), 
__.__("1").asNumber(N.nbigInt).next());
+    }
+
+    @Test
+    public void testStringToBigDecimal() {
+        assertEquals(new BigDecimal("0.0"), 
__.__("0.0").asNumber(N.nbigDecimal).next());
+        assertEquals(new 
BigDecimal("123456789012345678901234567890.123456789"),
+                
__.__("123456789012345678901234567890.123456789").asNumber(N.nbigDecimal).next());
+        assertEquals(new 
BigDecimal("-123456789012345678901234567890.123456789"),
+                
__.__("-123456789012345678901234567890.123456789").asNumber(N.nbigDecimal).next());
+        // Note directly constructing BigDecimal returns 1E-39, but parsing 
then converting from double results in 1.0E-39
+        
assertEquals(BigDecimal.valueOf(Double.parseDouble("0.000000000000000000000000000000000000001")),
+                
__.__("0.000000000000000000000000000000000000001").asNumber(N.nbigDecimal).next());
+        assertEquals(new BigDecimal("1.0"), 
__.__("1.0").asNumber(N.nbigDecimal).next());
+    }
+
+// ===== EDGE CASE TESTS =====
+
+    @Test
+    public void testCastInfinityAndNaN() {
+        assertEquals(Double.POSITIVE_INFINITY, 
__.__(Float.POSITIVE_INFINITY).asNumber(N.ndouble).next());
+        assertEquals(Double.NEGATIVE_INFINITY, 
__.__(Float.NEGATIVE_INFINITY).asNumber(N.ndouble).next());
+        assertEquals(Double.NaN, __.__(Float.NaN).asNumber(N.ndouble).next());
+        assertEquals(Float.POSITIVE_INFINITY, 
__.__(Double.POSITIVE_INFINITY).asNumber(N.nfloat).next());
+        assertEquals(Float.NEGATIVE_INFINITY, 
__.__(Double.NEGATIVE_INFINITY).asNumber(N.nfloat).next());
+        assertEquals(Float.NaN, __.__(Double.NaN).asNumber(N.nfloat).next());
+        assertEquals(Long.MAX_VALUE, 
__.__(Double.POSITIVE_INFINITY).asNumber(N.nlong).next());
+        assertEquals(0, __.__(Double.NaN).asNumber(N.nint).next());
+    }
+
+    @Test
+    public void testStringWithWhitespace() {
+        assertEquals(42, __.__(" 42 ").asNumber(N.nint).next());
+        assertEquals(42, __.__("\t42\n").asNumber(N.nint).next());
+        assertEquals(3.14, __.__(" 3.14 ").asNumber(N.ndouble).next());
+        assertEquals((byte) 127, __.__(" 127 ").asNumber(N.nbyte).next());
+    }
+
+    @Test
+    public void testStringWithPlusSign() {
+        assertEquals(42, __.__("+42").asNumber(N.nint).next());
+        assertEquals(3.14, __.__("+3.14").asNumber(N.ndouble).next());
+        assertEquals((byte) 42, __.__("+42").asNumber(N.nbyte).next());
+        assertEquals(new BigInteger("42"), 
__.__("+42").asNumber(N.nbigInt).next());
+    }
+
+    @Test
+    public void testZeroValues() {
+        assertEquals((byte) 0, __.__("0").asNumber(N.nbyte).next());
+        assertEquals((short) 0, __.__("0").asNumber(N.nshort).next());
+        assertEquals(0, __.__("0").asNumber(N.nint).next());
+        assertEquals(0L, __.__("0").asNumber(N.nlong).next());
+        assertEquals(0.0f, __.__("0.0").asNumber(N.nfloat).next());
+        assertEquals(0.0, __.__("0.0").asNumber(N.ndouble).next());
+        assertEquals(new BigInteger("0"), 
__.__("0").asNumber(N.nbigInt).next());
+        assertEquals(new BigDecimal("0.0"), 
__.__("0.0").asNumber(N.nbigDecimal).next());
+    }
+
+    @Test
+    public void testScientificNotation() {
+        assertEquals(1.23e10f, __.__("1.23e10").asNumber(N.nfloat).next());
+        assertEquals(1.23e10, __.__("1.23e10").asNumber(N.ndouble).next());
+        assertEquals(1.23e-10f, __.__("1.23e-10").asNumber(N.nfloat).next());
+        assertEquals(1.23e-10, __.__("1.23e-10").asNumber(N.ndouble).next());
+        assertEquals(new BigDecimal("1.23E10"), 
__.__("1.23e10").asNumber(N.nbigDecimal).next());
+    }
+
+// ===== OVERFLOW EXCEPTION TESTS =====
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringByteOverflowsPositive() {
+        __.__("128").asNumber(N.nbyte).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringByteOverflowsNegative() {
+        __.__("-129").asNumber(N.nbyte).next();
+
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringShortOverflowsPositive() 
{
+        __.__("32768").asNumber(N.nshort).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringShortOverflowsNegative() 
{
+        __.__("-32769").asNumber(N.nshort).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringIntOverflowsPositive() {
+        __.__("2147483648").asNumber(N.nint).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringIntOverflowsNegative() {
+        __.__("-2147483649").asNumber(N.nint).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringLongOverflowsPositive() {
+        __.__("9223372036854775809").asNumber(N.nlong).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenStringLongOverflowsNegative() {
+        __.__("-9223372036854775809").asNumber(N.nlong).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenDoubleStringToFloatOverflows() 
{
+        __.__("3.5E38").asNumber(N.nfloat).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void 
shouldThrowOverflowExceptionWhenBigDecimalStringToDoubleOverflows() {
+        __.__("1.8E308").asNumber(N.ndouble).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void 
shouldThrowOverflowExceptionWhenBigDecimalStringToFloatOverflows() {
+        __.__("1.8E308").asNumber(N.nfloat).next();
+    }
+
+// ===== INVALID FORMAT EXCEPTION TESTS =====
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenEmptyString() {
+        __.__("").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenWhitespaceOnlyString() {
+        __.__("   ").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenAlphabeticString() {
+        __.__("abc").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenMixedAlphanumericString() {
+        __.__("123abc456").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenSpecialCharactersString() {
+        __.__("12@34").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenMultipleDecimalPoints() {
+        __.__("12.34.56").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenMultipleSigns() {
+        __.__("++123").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenSignInMiddle() {
+        __.__("12+34").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenInvalidScientificNotation() {
+        __.__("12e").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenInvalidScientificNotationWithSign() {
+        __.__("12e+").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenInvalidDecimalFormat() {
+        __.__(".").asNumber().next();
+    }
+
+// ===== PRECISION AND BOUNDARY TESTS =====
+
+    @Test
+    public void testBoundaryValues() {
+        assertEquals(Byte.MAX_VALUE, __.__("127").asNumber(N.nbyte).next());
+        assertEquals(Byte.MIN_VALUE, __.__("-128").asNumber(N.nbyte).next());
+        assertEquals(Short.MAX_VALUE, 
__.__("32767").asNumber(N.nshort).next());
+        assertEquals(Short.MIN_VALUE, 
__.__("-32768").asNumber(N.nshort).next());
+        assertEquals(Integer.MAX_VALUE, 
__.__("2147483647").asNumber(N.nint).next());
+        assertEquals(Integer.MIN_VALUE, 
__.__("-2147483648").asNumber(N.nint).next());
+        assertEquals(Long.MAX_VALUE, 
__.__("9223372036854775807").asNumber(N.nlong).next());
+        assertEquals(Long.MIN_VALUE, 
__.__("-9223372036854775808").asNumber(N.nlong).next());
+    }
+
+    @Test
+    public void testHighPrecisionDecimals() {
+        assertEquals(new 
BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"),
+                
__.__("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067").asNumber(N.nbigDecimal).next());
+    }
+
+    @Test
+    public void testVeryLargeNumbers() {
+        String largeNumber = 
"12345678901234567890123456789012345678901234567890123456789012345678901234567890";
+        assertEquals(new BigInteger(largeNumber), 
__.__(largeNumber).asNumber(N.nbigInt).next());
+    }
+
 }
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/NumberHelperTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/NumberHelperTest.java
index 314be66fcb..ef88db95ce 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/NumberHelperTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/NumberHelperTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.util;
 
+import org.apache.tinkerpop.gremlin.process.traversal.N;
 import org.javatuples.Quartet;
 import org.javatuples.Triplet;
 import org.junit.Test;
@@ -709,4 +710,78 @@ public class NumberHelperTest {
         final Double value = 42.0;
         assertEquals(Float.valueOf(42.0f), NumberHelper.coerceTo(value, 
Float.class));
     }
+
+
+    @Test
+    public void shouldCastToReturnSameInstanceForSameClass() {
+        final Integer value = 42;
+        assertEquals(value, NumberHelper.castTo(value, N.nint));
+    }
+
+    @Test
+    public void shouldCastToConvertToByte() {
+        final Integer value = 42;
+        assertEquals(Byte.valueOf((byte) 42), NumberHelper.castTo(value, 
N.nbyte));
+    }
+
+    @Test
+    public void shouldCastToConvertToShort() {
+        final Integer value = 42;
+        assertEquals(Short.valueOf((short) 42), NumberHelper.castTo(value, 
N.nbyte));
+    }
+
+    @Test
+    public void shouldCastToConvertToLong() {
+        final Integer value = 42;
+        assertEquals(Long.valueOf(42L), NumberHelper.castTo(value, N.nlong));
+    }
+
+    @Test
+    public void shouldCastToConvertToFloat() {
+        final Integer value = 42;
+        assertEquals(Float.valueOf(42.0f), NumberHelper.castTo(value, 
N.nfloat));
+    }
+
+    @Test
+    public void shouldCastToConvertToDouble() {
+        final Integer value = 42;
+        assertEquals(Double.valueOf(42.0), NumberHelper.castTo(value, 
N.ndouble));
+    }
+
+    @Test
+    public void shouldCastToConvertToBigInteger() {
+        final Integer value = 42;
+        assertEquals(BigInteger.valueOf(42), NumberHelper.castTo(value, 
N.nbigInt));
+    }
+
+    @Test
+    public void shouldCastToConvertToBigDecimal() {
+        final Integer value = 42;
+        assertEquals(BigDecimal.valueOf(42), NumberHelper.castTo(value, 
N.nbigDecimal));
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldOverflowIfCannotFitInByte() {
+        final Integer value = 128;
+        NumberHelper.castTo(value, N.nbyte);
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldOverflowIfCannotFitInShort() {
+        final Integer value = 32768;
+        NumberHelper.castTo(value, N.nshort);
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldOverflowIfCannotFitInInteger() {
+        final Long value = 2147483648L;
+        NumberHelper.castTo(value, N.nint);
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldOverflowIfCannotFitInFloat() {
+        final Double value = Double.MAX_VALUE;
+        NumberHelper.castTo(value, N.nfloat);
+    }
+
 }
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
index 2a5972a067..70c2154841 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
@@ -100,7 +100,7 @@ Feature: Step - asNumber()
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[5.75].d |
+      | d[5.75].f |
 
   @GraphComputerVerificationInjectionNotSupported
   Scenario: g_injectX5_43X_asNumberXN_nintX


Reply via email to