Fixes issue #907 ("Float.valueOf() Acceptes Alpha Strings")
Patch by: bobv
Review by: tobyr, bruce
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@968 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/super/com/google/gwt/emul/java/lang/Byte.java b/user/super/com/google/gwt/emul/java/lang/Byte.java
index 2c0b658..b610af4 100644
--- a/user/super/com/google/gwt/emul/java/lang/Byte.java
+++ b/user/super/com/google/gwt/emul/java/lang/Byte.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2006 Google Inc.
- *
+ * Copyright 2007 Google Inc.
+ *
* Licensed 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
@@ -23,12 +23,7 @@
public static final byte MAX_VALUE = (byte) 0x7F;
public static Byte decode(String s) throws NumberFormatException {
- long x = __parseLongInfer(s);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return new Byte((byte) x);
- }
+ return new Byte((byte)__decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
}
public static byte parseByte(String s) throws NumberFormatException {
@@ -38,12 +33,7 @@
public static byte parseByte(String s, int radix)
throws NumberFormatException {
- long x = __parseLongRadix(s, radix);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return (byte) x;
- }
+ return (byte)__parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
}
public static String toString(byte b) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Double.java b/user/super/com/google/gwt/emul/java/lang/Double.java
index 66dcabd..c33d36a 100644
--- a/user/super/com/google/gwt/emul/java/lang/Double.java
+++ b/user/super/com/google/gwt/emul/java/lang/Double.java
@@ -44,12 +44,7 @@
}-*/;
public static double parseDouble(String s) throws NumberFormatException {
- double x = __parseDouble(s);
- if (isNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return x;
- }
+ return __parseAndValidateDouble(s);
}
public static String toString(double b) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Float.java b/user/super/com/google/gwt/emul/java/lang/Float.java
index d7e69f3..d01dd1f 100644
--- a/user/super/com/google/gwt/emul/java/lang/Float.java
+++ b/user/super/com/google/gwt/emul/java/lang/Float.java
@@ -44,12 +44,7 @@
}-*/;
public static float parseFloat(String s) throws NumberFormatException {
- float x = __parseFloat(s);
- if (isNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return x;
- }
+ return (float)__parseAndValidateDouble(s);
}
public static String toString(float b) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Integer.java b/user/super/com/google/gwt/emul/java/lang/Integer.java
index 6c197f3..9640d8f 100644
--- a/user/super/com/google/gwt/emul/java/lang/Integer.java
+++ b/user/super/com/google/gwt/emul/java/lang/Integer.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2006 Google Inc.
- *
+ * Copyright 2007 Google Inc.
+ *
* Licensed 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
@@ -23,12 +23,7 @@
public static final int MAX_VALUE = 0x7fffffff;
public static Integer decode(String s) throws NumberFormatException {
- long x = __parseLongInfer(s);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return new Integer((int) x);
- }
+ return new Integer((int)__decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
}
public static int parseInt(String s) throws NumberFormatException {
@@ -36,12 +31,7 @@
}
public static int parseInt(String s, int radix) throws NumberFormatException {
- long x = __parseLongRadix(s, radix);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return (int) x;
- }
+ return (int)__parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
}
public static String toBinaryString(int x) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Long.java b/user/super/com/google/gwt/emul/java/lang/Long.java
index f5f0d09..eb321ff 100644
--- a/user/super/com/google/gwt/emul/java/lang/Long.java
+++ b/user/super/com/google/gwt/emul/java/lang/Long.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2006 Google Inc.
- *
+ * Copyright 2007 Google Inc.
+ *
* Licensed 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
@@ -23,12 +23,7 @@
public static final long MAX_VALUE = 0x7fffffffffffffffL;
public static Long decode(String s) throws NumberFormatException {
- long x = __parseLongInfer(s);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return new Long(x);
- }
+ return new Long(__decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
}
public static long parseLong(String s) throws NumberFormatException {
@@ -37,12 +32,7 @@
public static long parseLong(String s, int radix)
throws NumberFormatException {
- long x = __parseLongRadix(s, radix);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return x;
- }
+ return __parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
}
public static String toBinaryString(long x) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Number.java b/user/super/com/google/gwt/emul/java/lang/Number.java
index 71ebf84..c848490 100644
--- a/user/super/com/google/gwt/emul/java/lang/Number.java
+++ b/user/super/com/google/gwt/emul/java/lang/Number.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2006 Google Inc.
- *
+ * Copyright 2007 Google Inc.
+ *
* Licensed 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
@@ -15,11 +15,18 @@
*/
package java.lang;
+import com.google.gwt.core.client.JavaScriptObject;
+
/**
* Abstract base class for numberic wrapper classes.
*/
public abstract class Number {
+ /**
+ * Stores a regular expression object to verify format of float values.
+ */
+ protected static JavaScriptObject floatRegex;
+
// CHECKSTYLE_OFF: A special need to use unusual identifiers to avoid
// introducing name collisions.
@@ -30,43 +37,149 @@
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
"e", "f"};
+ static {
+ initNative();
+ }
+
+ private static native void initNative() /*-{
+ @java.lang.Number::floatRegex = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/i;
+ }-*/;
+
+ /**
+ * @skip
+ *
+ * This function will determine the radix that the string is expressed in
+ * based on the parsing rules defined in the Javadocs for Integer.decode() and
+ * invoke __parseAndValidateLong.
+ */
+ protected static long __decodeAndValidateLong(String s, long lowerBound,
+ long upperBound) throws NumberFormatException {
+ final boolean negative;
+ if (s.startsWith("-")) {
+ negative = true;
+ s = s.substring(1);
+ } else {
+ negative = false;
+ }
+
+ final int radix;
+ if (s.startsWith("0x") || s.startsWith("0X")) {
+ s = s.substring(2);
+ radix = 16;
+ } else if (s.startsWith("#")) {
+ s = s.substring(1);
+ radix = 16;
+ } else if (s.startsWith("0")) {
+ radix = 8;
+ } else {
+ radix = 10;
+ }
+
+ if (negative) {
+ s = "-" + s;
+ }
+
+ return __parseAndValidateLong(s, radix, lowerBound, upperBound);
+ }
+
+ /**
+ * @skip
+ *
+ * This function contains common logic for parsing a String in a given
+ * radix and validating the result.
+ */
+ protected static long __parseAndValidateLong(String s, int radix,
+ long lowerBound, long upperBound) throws NumberFormatException {
+
+ int length = s.length();
+ int startIndex = (length > 0) && (s.charAt(0) == '-') ? 1 : 0;
+
+ for (int i = startIndex; i < length; i++) {
+ if (Character.digit(s.charAt(i), radix) == -1) {
+ throw new NumberFormatException("Could not parse " + s +
+ " in radix " + radix);
+ }
+ }
+
+ long toReturn = __parseInt(s, radix);
+ if (__isLongNaN(toReturn)) {
+ throw new NumberFormatException("Unable to parse " + s);
+ } else if (toReturn < lowerBound || toReturn > upperBound) {
+ throw new NumberFormatException(
+ "The string " + s + " exceeds the range for the requested data type");
+ }
+
+ return toReturn;
+ }
+
+ /**
+ * @skip
+ *
+ * This function contains common logic for parsing a String as a floating-
+ * point number and validating the range.
+ */
+ protected static double __parseAndValidateDouble(String s)
+ throws NumberFormatException {
+
+ double toReturn = __parseDouble(s);
+
+ if (__isDoubleNaN(toReturn)) {
+ throw new NumberFormatException("Unable to parse " + s);
+ }
+
+ return toReturn;
+ }
+
/**
* @skip
*/
- protected static native boolean __isLongNaN(long x) /*-{
+ private static native boolean __isDoubleNaN(double x) /*-{
return isNaN(x);
}-*/;
/**
* @skip
*/
- protected static native long __parseLongRadix(String s, int radix) /*-{
+ private static native boolean __isLongNaN(long x) /*-{
+ return isNaN(x);
+ }-*/;
+
+ /**
+ * @skip
+ *
+ * Invokes the global JS function <code>parseInt()</code>.
+ */
+ private static native long __parseInt(String s, int radix) /*-{
return parseInt(s, radix);
}-*/;
-
+
/**
* @skip
+ *
+ * @return The floating-point representation of <code>str</code> or
+ * <code>Number.NaN</code> if the string does not match
+ * {@link floatRegex}.
*/
- protected static native long __parseLongInfer(String s) /*-{
- return parseInt(s);
- }-*/;
-
- /**
- * @skip
- */
- protected static native double __parseDouble(String str) /*-{
- return parseFloat(str);
- }-*/;
-
- /**
- * @skip
- */
- static native float __parseFloat(String str) /*-{
- return parseFloat(str);
+ private static native double __parseDouble(String str) /*-{
+ if (@java.lang.Number::floatRegex.test(str)) {
+ return parseFloat(str);
+ } else {
+ return Number.NaN;
+ }
}-*/;
// CHECKSTYLE_ON
+ /**
+ * Used by JSNI methods to report badly formatted strings.
+ * @param s the unparseable string
+ * @throws NumberFormatException every time
+ */
+ private static void throwNumberFormatException(String s)
+ throws NumberFormatException {
+ throw new NumberFormatException("Could not parse " + s);
+ }
+
public abstract byte byteValue();
public abstract double doubleValue();
diff --git a/user/super/com/google/gwt/emul/java/lang/Short.java b/user/super/com/google/gwt/emul/java/lang/Short.java
index 46e5939..53c3e18 100644
--- a/user/super/com/google/gwt/emul/java/lang/Short.java
+++ b/user/super/com/google/gwt/emul/java/lang/Short.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2006 Google Inc.
- *
+ * Copyright 2007 Google Inc.
+ *
* Licensed 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
@@ -23,12 +23,7 @@
public static final short MAX_VALUE = (short) 0x7fff;
public static Short decode(String s) throws NumberFormatException {
- long x = __parseLongInfer(s);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return new Short((short) x);
- }
+ return new Short((short)__decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
}
public static short parseShort(String s) throws NumberFormatException {
@@ -37,12 +32,7 @@
public static short parseShort(String s, int radix)
throws NumberFormatException {
- long x = __parseLongRadix(s, radix);
- if (__isLongNaN(x)) {
- throw new NumberFormatException(s);
- } else {
- return (short) x;
- }
+ return (short)__parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
}
public static String toString(short b) {
diff --git a/user/test/com/google/gwt/emultest/java/lang/DoubleTest.java b/user/test/com/google/gwt/emultest/java/lang/DoubleTest.java
index 88756c5..4d6edaa 100644
--- a/user/test/com/google/gwt/emultest/java/lang/DoubleTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/DoubleTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 Google Inc.
- *
+ *
* Licensed 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
@@ -27,12 +27,49 @@
return "com.google.gwt.emultest.EmulSuite";
}
+ public void testBadStrings() {
+ try {
+ new Double("0.0e");
+ fail("constructor");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Double.parseDouble("0.0e");
+ fail("parse");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Double.valueOf("0x0e");
+ fail("valueOf");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+ }
+
public void testDoubleConstants() {
assertTrue(Double.isNaN(Double.NaN));
assertTrue(Double.isInfinite(Double.NEGATIVE_INFINITY));
assertTrue(Double.isInfinite(Double.POSITIVE_INFINITY));
assertTrue(Double.NEGATIVE_INFINITY < Double.POSITIVE_INFINITY);
+ assertTrue(Double.MIN_VALUE < Double.MAX_VALUE);
assertFalse(Double.NaN == Double.NaN);
}
+ public void testParse() {
+ assertTrue(0 == Double.parseDouble("0"));
+ assertTrue(-1.5 == Double.parseDouble("-1.5"));
+ assertTrue(3.0 == Double.parseDouble("3."));
+ assertTrue(0.5 == Double.parseDouble(".5"));
+ assertTrue(2.98e8 == Double.parseDouble("2.98e8"));
+ assertTrue(-2.98e-8 == Double.parseDouble("-2.98e-8"));
+ assertTrue(+2.98E+8 == Double.parseDouble("+2.98E+8"));
+ assertTrue("Can't parse MIN_VALUE",
+ Double.MIN_VALUE == Double.parseDouble(String.valueOf(Double.MIN_VALUE)));
+ assertTrue("Can't parse MAX_VALUE",
+ Double.MAX_VALUE == Double.parseDouble(String.valueOf(Double.MAX_VALUE)));
+ }
}
diff --git a/user/test/com/google/gwt/emultest/java/lang/FloatTest.java b/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
index 1d7faa6..5c145d2 100644
--- a/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 Google Inc.
- *
+ *
* Licensed 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
@@ -27,12 +27,46 @@
return "com.google.gwt.emultest.EmulSuite";
}
+ public void testBadStrings() {
+ try {
+ new Float("0.0e");
+ fail("constructor");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Float.parseFloat("0.0e");
+ fail("parse");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Float.valueOf("0x0e");
+ fail("valueOf");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+ }
+
public void testFloatConstants() {
assertTrue(Float.isNaN(Float.NaN));
assertTrue(Float.isInfinite(Float.NEGATIVE_INFINITY));
assertTrue(Float.isInfinite(Float.POSITIVE_INFINITY));
assertTrue(Float.NEGATIVE_INFINITY < Float.POSITIVE_INFINITY);
+ assertTrue(Float.MIN_VALUE < Float.MAX_VALUE);
assertFalse(Float.NaN == Float.NaN);
}
+ public void testParse() {
+ assertTrue(0 == Float.parseFloat("0"));
+ assertTrue(-1.5 == Float.parseFloat("-1.5"));
+ assertTrue(3.0 == Float.parseFloat("3."));
+ assertTrue(0.5 == Float.parseFloat(".5"));
+ assertTrue("Can't parse MAX_VALUE",
+ Float.MAX_VALUE == Float.parseFloat(String.valueOf(Float.MAX_VALUE)));
+ assertTrue("Can't parse MIN_VALUE",
+ Float.MIN_VALUE == Float.parseFloat(String.valueOf(Float.MIN_VALUE)));
+ }
}
diff --git a/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java b/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
index a16f6dc..a53c08a 100644
--- a/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 Google Inc.
- *
+ *
* Licensed 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
@@ -36,6 +36,57 @@
assertEquals("-12345", new Integer("-12345").toString());
}
+ public void testBadStrings() {
+ try {
+ new Integer("05abcd");
+ fail("Constructor should have thrown NumberFormatException");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.decode("05abcd");
+ fail("Decode should have thrown NumberFormatException");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.parseInt("05abcd");
+ fail("parseInt should have thrown NumberFormatException");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.parseInt(String.valueOf(Long.MAX_VALUE));
+ fail("parseInt should reject numbers greater than the range of int");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.parseInt(String.valueOf(Long.MIN_VALUE));
+ fail("parseInt should reject numbers less than the range of int");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.parseInt(String.valueOf((long)Integer.MAX_VALUE + 1));
+ fail("parseInt should reject numbers greater than the range of int");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+
+ try {
+ Integer.parseInt(String.valueOf((long)Integer.MIN_VALUE - 1));
+ fail("parseInt should reject numbers less than the range of int");
+ } catch (NumberFormatException e) {
+ // Expected behavior
+ }
+ }
+
public void testCompareTo() {
assertEquals(-1, new Integer(12345).compareTo(new Integer(12346)));
assertEquals(1, new Integer("12345").compareTo(new Integer(12344)));
@@ -48,7 +99,15 @@
}
public void testDecode() {
+ assertEquals(Integer.MAX_VALUE,
+ Integer.decode(String.valueOf(Integer.MAX_VALUE)).intValue());
+ assertEquals(Integer.MIN_VALUE,
+ Integer.decode(String.valueOf(Integer.MIN_VALUE)).intValue());
assertEquals(12345, Integer.decode("12345").intValue());
+ assertEquals(31, Integer.decode("0x1f").intValue());
+ assertEquals(-31, Integer.decode("-0X1F").intValue());
+ assertEquals(31, Integer.decode("#1f").intValue());
+ assertEquals(10, Integer.decode("012").intValue());
try {
Integer.decode("abx");
fail();