8041972: Additional parse methods for Long/Integer

Reviewed-by: mduigou, psandoz
This commit is contained in:
Claes Redestad 2014-07-12 01:36:25 +02:00
parent 9f7993fe13
commit 59d0a64c19
5 changed files with 747 additions and 47 deletions

View File

@ -26,6 +26,7 @@
package java.lang;
import java.lang.annotation.Native;
import java.util.Objects;
/**
* The {@code Integer} class wraps a value of the primitive type
@ -549,12 +550,9 @@ public final class Integer extends Number implements Comparable<Integer> {
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@ -562,21 +560,21 @@ public final class Integer extends Number implements Comparable<Integer> {
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
}
i++;
}
int multmin = limit / radix;
int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@ -585,10 +583,126 @@ public final class Integer extends Number implements Comparable<Integer> {
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
/**
* Parses the {@link CharSequence} argument as a signed {@code int} in the
* specified {@code radix}, beginning at the specified {@code beginIndex}
* and extending to the end of the sequence.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the {@code int}
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @return the signed {@code int} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable {@code int} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static int parseInt(CharSequence s, int radix, int beginIndex)
throws NumberFormatException {
// forces an implicit null check of s
return parseInt(s, radix, beginIndex, s.length());
}
/**
* Parses the {@link CharSequence} argument as a signed {@code int} in the
* specified {@code radix}, beginning at the specified {@code beginIndex}
* and extending to {@code endIndex - 1}.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the {@code int}
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the signed {@code int} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code endIndex} or if {@code endIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable {@code int} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
boolean negative = false;
int i = beginIndex;
int limit = -Integer.MAX_VALUE;
if (i < endIndex) {
char firstChar = s.charAt(i);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
i++;
if (i == endIndex) { // Cannot have lone "+" or "-"
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
}
int multmin = limit / radix;
int result = 0;
while (i < endIndex) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString("");
}
}
/**
@ -688,6 +802,99 @@ public final class Integer extends Number implements Comparable<Integer> {
}
}
/**
* Parses the {@link CharSequence} argument as an unsigned {@code int} in
* the specified {@code radix}, beginning at the specified
* {@code beginIndex} and extending to the end of the sequence.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the unsigned
* {@code int} representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @return the unsigned {@code int} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable unsigned {@code int} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex)
throws NumberFormatException {
// forces an implicit null check of s
return parseUnsignedInt(s, radix, beginIndex, s.length());
}
/**
* Parses the {@link CharSequence} argument as an unsigned {@code int} in
* the specified {@code radix}, beginning at the specified
* {@code beginIndex} and extending to {@code endIndex - 1}.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the unsigned
* {@code int} representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the unsigned {@code int} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code endIndex} or if {@code endIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable unsigned {@code int} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex, int endIndex)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
int start = beginIndex, len = endIndex - beginIndex;
if (len > 0) {
char firstChar = s.charAt(start);
if (firstChar == '-') {
throw new
NumberFormatException(String.format("Illegal leading minus sign " +
"on unsigned string %s.", s));
} else {
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
(radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
return parseInt(s, radix, start, start + len);
} else {
long ell = Long.parseLong(s, radix, start, start + len);
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
return (int) ell;
} else {
throw new
NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned int.", s));
}
}
}
} else {
throw new NumberFormatException("");
}
}
/**
* Parses the string argument as an unsigned decimal integer. The
* characters in the string must all be decimal digits, except

View File

@ -27,6 +27,7 @@ package java.lang;
import java.lang.annotation.Native;
import java.math.*;
import java.util.Objects;
/**
@ -561,12 +562,9 @@ public final class Long extends Number implements Comparable<Long> {
" greater than Character.MAX_RADIX");
}
long result = 0;
boolean negative = false;
int i = 0, len = s.length();
long limit = -Long.MAX_VALUE;
long multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
@ -574,21 +572,21 @@ public final class Long extends Number implements Comparable<Long> {
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
}
i++;
}
long multmin = limit / radix;
long result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++),radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
@ -597,10 +595,126 @@ public final class Long extends Number implements Comparable<Long> {
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
/**
* Parses the {@link CharSequence} argument as a signed {@code long} in
* the specified {@code radix}, beginning at the specified {@code beginIndex}
* and extending to the end of the sequence.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the {@code long}
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @return the signed {@code long} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable {@code long} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static long parseLong(CharSequence s, int radix, int beginIndex)
throws NumberFormatException {
// forces a null check of s
return parseLong(s, radix, beginIndex, s.length());
}
/**
* Parses the {@link CharSequence} argument as a signed {@code long} in
* the specified {@code radix}, beginning at the specified
* {@code beginIndex} and extending to {@code endIndex - 1}.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the {@code long}
* representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the signed {@code long} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code endIndex} or if {@code endIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable {@code int} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
boolean negative = false;
int i = beginIndex;
long limit = -Long.MAX_VALUE;
if (i < endIndex) {
char firstChar = s.charAt(i);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Long.MIN_VALUE;
} else if (firstChar != '+') {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
i++;
}
if (i >= endIndex) { // Cannot have lone "+", "-" or ""
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
long multmin = limit / radix;
long result = 0;
while (i < endIndex) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forCharSequence(s, beginIndex,
endIndex, i);
}
result -= digit;
}
return negative ? result : -result;
} else {
throw new NumberFormatException("");
}
}
/**
@ -694,7 +808,7 @@ public final class Long extends Number implements Comparable<Long> {
}
// No need for range checks on len due to testing above.
long first = parseLong(s.substring(0, len - 1), radix);
long first = parseLong(s, radix, 0, len - 1);
int second = Character.digit(s.charAt(len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " + s);
@ -763,6 +877,155 @@ public final class Long extends Number implements Comparable<Long> {
}
}
/**
* Parses the {@link CharSequence} argument as an unsigned {@code long} in
* the specified {@code radix}, beginning at the specified
* {@code beginIndex} and extending to the end of the sequence.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the unsigned
* {@code long} representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @return the unsigned {@code long} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable unsigned {@code long} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex)
throws NumberFormatException {
// forces a null check of s
return parseUnsignedLong(s, radix, beginIndex, s.length());
}
/**
* Parses the {@link CharSequence} argument as an unsigned {@code long} in
* the specified {@code radix}, beginning at the specified
* {@code beginIndex} and extending to {@code endIndex - 1}.
*
* <p>The method does not take steps to guard against the
* {@code CharSequence} being mutated while parsing.
*
* @param s the {@code CharSequence} containing the unsigned
* {@code long} representation to be parsed
* @param radix the radix to be used while parsing {@code s}.
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the unsigned {@code long} represented by the subsequence in
* the specified radix.
* @throws NullPointerException if {@code s} is null.
* @throws IndexOutOfBoundsException if {@code beginIndex} is
* negative, or if {@code beginIndex} is greater than
* {@code endIndex} or if {@code endIndex} is greater than
* {@code s.length()}.
* @throws NumberFormatException if the {@code CharSequence} does not
* contain a parsable unsigned {@code long} in the specified
* {@code radix}, or if {@code radix} is either smaller than
* {@link java.lang.Character#MIN_RADIX} or larger than
* {@link java.lang.Character#MAX_RADIX}.
* @since 1.9
*/
public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex, int endIndex)
throws NumberFormatException {
s = Objects.requireNonNull(s);
if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
throw new IndexOutOfBoundsException();
}
int start = beginIndex, len = endIndex - beginIndex;
if (len > 0) {
char firstChar = s.charAt(start);
if (firstChar == '-') {
throw new NumberFormatException(String.format("Illegal leading minus sign " +
"on unsigned string %s.", s.subSequence(start, start + len)));
} else {
if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
(radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
return parseLong(s, radix, start, start + len);
}
// No need for range checks on end due to testing above.
long first = parseLong(s, radix, start, start + len - 1);
int second = Character.digit(s.charAt(start + len - 1), radix);
if (second < 0) {
throw new NumberFormatException("Bad digit at end of " +
s.subSequence(start, start + len));
}
long result = first * radix + second;
/*
* Test leftmost bits of multiprecision extension of first*radix
* for overflow. The number of bits needed is defined by
* GUARD_BIT = ceil(log2(Character.MAX_RADIX)) + 1 = 7. Then
* int guard = radix*(int)(first >>> (64 - GUARD_BIT)) and
* overflow is tested by splitting guard in the ranges
* guard < 92, 92 <= guard < 128, and 128 <= guard, where
* 92 = 128 - Character.MAX_RADIX. Note that guard cannot take
* on a value which does not include a prime factor in the legal
* radix range.
*/
int guard = radix * (int) (first >>> 57);
if (guard >= 128 ||
(result >= 0 && guard >= 128 - Character.MAX_RADIX)) {
/*
* For purposes of exposition, the programmatic statements
* below should be taken to be multi-precision, i.e., not
* subject to overflow.
*
* A) Condition guard >= 128:
* If guard >= 128 then first*radix >= 2^7 * 2^57 = 2^64
* hence always overflow.
*
* B) Condition guard < 92:
* Define left7 = first >>> 57.
* Given first = (left7 * 2^57) + (first & (2^57 - 1)) then
* result <= (radix*left7)*2^57 + radix*(2^57 - 1) + second.
* Thus if radix*left7 < 92, radix <= 36, and second < 36,
* then result < 92*2^57 + 36*(2^57 - 1) + 36 = 2^64 hence
* never overflow.
*
* C) Condition 92 <= guard < 128:
* first*radix + second >= radix*left7*2^57 + second
* so that first*radix + second >= 92*2^57 + 0 > 2^63
*
* D) Condition guard < 128:
* radix*first <= (radix*left7) * 2^57 + radix*(2^57 - 1)
* so
* radix*first + second <= (radix*left7) * 2^57 + radix*(2^57 - 1) + 36
* thus
* radix*first + second < 128 * 2^57 + 36*2^57 - radix + 36
* whence
* radix*first + second < 2^64 + 2^6*2^57 = 2^64 + 2^63
*
* E) Conditions C, D, and result >= 0:
* C and D combined imply the mathematical result
* 2^63 < first*radix + second < 2^64 + 2^63. The lower
* bound is therefore negative as a signed long, but the
* upper bound is too small to overflow again after the
* signed long overflows to positive above 2^64 - 1. Hence
* result >= 0 implies overflow given C and D.
*/
throw new NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned long.", s.subSequence(start, start + len)));
}
return result;
}
} else {
throw NumberFormatException.forInputString("");
}
}
/**
* Parses the string argument as an unsigned decimal {@code long}. The
* characters in the string must all be decimal digits, except

View File

@ -56,7 +56,7 @@ class NumberFormatException extends IllegalArgumentException {
}
/**
* Factory method for making a <code>NumberFormatException</code>
* Factory method for making a {@code NumberFormatException}
* given the specified input which caused the error.
*
* @param s the input causing the error
@ -64,4 +64,20 @@ class NumberFormatException extends IllegalArgumentException {
static NumberFormatException forInputString(String s) {
return new NumberFormatException("For input string: \"" + s + "\"");
}
/**
* Factory method for making a {@code NumberFormatException}
* given the specified input which caused the error.
*
* @param s the input causing the error
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @param errorIndex the index of the first error in s
*/
static NumberFormatException forCharSequence(CharSequence s,
int beginIndex, int endIndex, int errorIndex) {
return new NumberFormatException("Error at index "
+ (errorIndex - beginIndex) + " in: \""
+ s.subSequence(beginIndex, endIndex) + "\"");
}
}

View File

@ -23,29 +23,37 @@
/*
* @test
* @bug 5017980 6576055
* @bug 5017980 6576055 8041972
* @summary Test parsing methods
* @author Joseph D. Darcy
*/
import java.lang.IllegalArgumentException;
import java.lang.IndexOutOfBoundsException;
import java.lang.NullPointerException;
import java.lang.RuntimeException;
/**
* There are six methods in java.lang.Integer which transform strings
* There are eight methods in java.lang.Integer which transform strings
* into an int or Integer value:
*
* public Integer(String s)
* public static Integer decode(String nm)
* public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex)
* public static int parseInt(CharSequence s, int radix, int beginIndex)
* public static int parseInt(String s, int radix)
* public static int parseInt(String s)
* public static Integer valueOf(String s, int radix)
* public static Integer valueOf(String s)
*
* Besides decode, all the methods and constructor call down into
* parseInt(String, int) to do the actual work. Therefore, the
* behavior of parseInt(String, int) will be tested here.
* parseInt(CharSequence, int, int, int) to do the actual work. Therefore, the
* behavior of parseInt(CharSequence, int, int, int) will be tested here.
*
*/
public class ParsingTest {
public static void main(String... argv) {
check("+100", +100);
check("-100", -100);
@ -55,10 +63,14 @@ public class ParsingTest {
check("+00000", 0);
check("-00000", 0);
check("+00000", 0, 0, 6);
check("-00000", 0, 0, 6);
check("0", 0);
check("1", 1);
check("9", 9);
checkFailure("");
checkFailure("\u0000");
checkFailure("\u002f");
checkFailure("+");
@ -72,12 +84,45 @@ public class ParsingTest {
checkFailure("+-6");
checkFailure("-+6");
checkFailure("*100");
check("test-00000", 0, 4, 10);
check("test-12345", -12345, 4, 10);
check("xx12345yy", 12345, 2, 7);
checkNumberFormatException("", 10, 0);
checkNumberFormatException("100", 10, 3);
checkNumberFormatException("+1000000", 10, 8);
checkNumberFormatException("-1000000", 10, 8);
checkNumberFormatException("", 10, 0, 0);
checkNumberFormatException("+-6", 10, 0, 3);
checkNumberFormatException("1000000", 10, 7);
checkNumberFormatException("1000000", 10, 7, 7);
checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2);
checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2);
checkIndexOutOfBoundsException("1000000", 10, 8);
checkIndexOutOfBoundsException("1000000", 10, -1);
checkIndexOutOfBoundsException("1000000", 10, 10, 4);
checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2);
checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2);
checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2);
checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2);
checkIndexOutOfBoundsException("-1", 10, 0, 3);
checkIndexOutOfBoundsException("-1", 10, 2, 3);
checkIndexOutOfBoundsException("-1", 10, -1, 2);
checkNull(10, 0, 1);
checkNull(10, -1, 0);
checkNull(10, 0, 0);
checkNull(10, 0, -1);
checkNull(-1, -1, -1);
}
private static void check(String val, int expected) {
int n = Integer.parseInt(val);
if (n != expected)
throw new RuntimeException("Integer.parsedInt failed. String:" +
throw new RuntimeException("Integer.parseInt failed. String:" +
val + " Result:" + n);
}
@ -91,4 +136,71 @@ public class ParsingTest {
; // Expected
}
}
private static void checkNumberFormatException(String val, int radix, int start) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start);
System.err.println("parseInt(" + val + ", " + radix + ", " + start +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NumberFormatException nfe) {
; // Expected
}
}
private static void checkNumberFormatException(String val, int radix, int start, int end) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start, end);
System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NumberFormatException nfe) {
; // Expected
}
}
private static void checkIndexOutOfBoundsException(String val, int radix, int start) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start);
System.err.println("parseInt(" + val + ", " + radix + ", " + start +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (IndexOutOfBoundsException ioob) {
; // Expected
}
}
private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start, end);
System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (IndexOutOfBoundsException ioob) {
; // Expected
}
}
private static void checkNull(int radix, int start, int end) {
int n = 0;
try {
n = Integer.parseInt(null, 10, start, end);
System.err.println("parseInt(null, " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NullPointerException npe) {
; // Expected
}
}
private static void check(String val, int expected, int start, int end) {
int n = Integer.parseInt(val, 10, start, end);
if (n != expected)
throw new RuntimeException("Integer.parsedInt failed. String:" +
val + ", start: " + start + ", end: " + end + " Result:" + n);
}
}

View File

@ -23,29 +23,31 @@
/*
* @test
* @bug 5017980 6576055
* @bug 5017980 6576055 8041972
* @summary Test parsing methods
* @author Joseph D. Darcy
*/
/**
* There are six methods in java.lang.Long which transform strings
* There are eight methods in java.lang.Long which transform strings
* into a long or Long value:
*
* public Long(String s)
* public static Long decode(String nm)
* public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
* public static long parseLong(CharSequence s, int radix, int beginIndex)
* public static long parseLong(String s, int radix)
* public static long parseLong(String s)
* public static Long valueOf(String s, int radix)
* public static Long valueOf(String s)
*
* Besides decode, all the methods and constructor call down into
* parseLong(String, int) to do the actual work. Therefore, the
* behavior of parseLong(String, int) will be tested here.
* parseLong(CharSequence, int, int, int) to do the actual work. Therefore, the
* behavior of parseLong(CharSequence, int, int, int) will be tested here.
*/
public class ParsingTest {
public static void main(String... argv) {
check("+100", +100L);
check("-100", -100L);
@ -59,6 +61,7 @@ public class ParsingTest {
check("1", 1L);
check("9", 9L);
checkFailure("");
checkFailure("\u0000");
checkFailure("\u002f");
checkFailure("+");
@ -72,12 +75,44 @@ public class ParsingTest {
checkFailure("+-6");
checkFailure("-+6");
checkFailure("*100");
check("test-00000", 0L, 4, 10);
check("test-12345", -12345L, 4, 10);
check("xx12345yy", 12345L, 2, 7);
check("xx123456789012345yy", 123456789012345L, 2, 17);
checkNumberFormatException("100", 10, 3);
checkNumberFormatException("", 10, 0);
checkNumberFormatException("+1000000", 10, 8);
checkNumberFormatException("-1000000", 10, 8);
checkNumberFormatException("", 10, 0, 0);
checkNumberFormatException("+-6", 10, 0, 3);
checkNumberFormatException("1000000", 10, 7, 7);
checkNumberFormatException("1000000", Character.MAX_RADIX + 1, 0, 2);
checkNumberFormatException("1000000", Character.MIN_RADIX - 1, 0, 2);
checkIndexOutOfBoundsException("", 10, 1, 1);
checkIndexOutOfBoundsException("1000000", 10, 10, 4);
checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, 10, 2);
checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, 10, 2);
checkIndexOutOfBoundsException("1000000", Character.MAX_RADIX + 1, -1, 2);
checkIndexOutOfBoundsException("1000000", Character.MIN_RADIX - 1, -1, 2);
checkIndexOutOfBoundsException("-1", 10, 0, 3);
checkIndexOutOfBoundsException("-1", 10, 2, 3);
checkIndexOutOfBoundsException("-1", 10, -1, 2);
checkNull(10, 0, 1);
checkNull(10, -1, 0);
checkNull(10, 0, 0);
checkNull(10, 0, -1);
checkNull(-1, -1, -1);
}
private static void check(String val, long expected) {
long n = Long.parseLong(val);
if (n != expected)
throw new RuntimeException("Long.parsedLong failed. String:" +
throw new RuntimeException("Long.parseLong failed. String:" +
val + " Result:" + n);
}
@ -91,4 +126,71 @@ public class ParsingTest {
; // Expected
}
}
private static void checkNumberFormatException(String val, int radix, int start) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start);
System.err.println("parseInt(" + val + ", " + radix + ", " + start +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NumberFormatException nfe) {
; // Expected
}
}
private static void checkNumberFormatException(String val, int radix, int start, int end) {
long n = 0;
try {
n = Long.parseLong(val, radix, start, end);
System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NumberFormatException nfe) {
; // Expected
}
}
private static void checkIndexOutOfBoundsException(String val, int radix, int start) {
int n = 0;
try {
n = Integer.parseInt(val, radix, start);
System.err.println("parseInt(" + val + ", " + radix + ", " + start +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (IndexOutOfBoundsException ioob) {
; // Expected
}
}
private static void checkIndexOutOfBoundsException(String val, int radix, int start, int end) {
long n = 0;
try {
n = Long.parseLong(val, radix, start, end);
System.err.println("parseInt(" + val + ", " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (IndexOutOfBoundsException ioob) {
; // Expected
}
}
private static void checkNull(int radix, int start, int end) {
long n = 0;
try {
n = Long.parseLong(null, 10, start, end);
System.err.println("parseInt(null, " + radix + ", " + start + ", " + end +
") incorrectly returned " + n);
throw new RuntimeException();
} catch (NullPointerException npe) {
; // Expected
}
}
private static void check(String val, long expected, int start, int end) {
long n = Long.parseLong(val, 10, start, end);
if (n != expected)
throw new RuntimeException("Long.parseLong failed. String:" +
val + ", start: " + start + ", end: " + end + " Result:" + n);
}
}