8335668: NumberFormat integer only parsing should throw exception for edge case

Reviewed-by: naoto
This commit is contained in:
Justin Lu 2024-07-11 18:40:40 +00:00
parent 58c98420b6
commit 5100303c6c
3 changed files with 67 additions and 11 deletions
src/java.base/share/classes/java/text
test/jdk/java/text/Format/NumberFormat

@ -2379,8 +2379,8 @@ public class DecimalFormat extends NumberFormat {
NumericPosition pos = subparseNumber(text, position, digits, true, isExponent, status);
position = pos.fullPos;
// First character after the prefix was un-parseable, should
// fail regardless if lenient or strict.
// First character after the prefix was un-parseable or parsing integer
// only with no integer portion. Should fail regardless if lenient or strict.
if (position == -1) {
parsePosition.index = oldStart;
parsePosition.errorIndex = oldStart;
@ -2421,8 +2421,8 @@ public class DecimalFormat extends NumberFormat {
}
// When parsing integer only, index should be int pos
// If intPos is 0, the entire value was integer
if (isParseIntegerOnly() && pos.intPos > 0) {
// If intPos is -1, the entire value was integer and index should be full pos
if (isParseIntegerOnly() && pos.intPos != -1) {
parsePosition.index = pos.intPos;
} else {
// increment the index by the suffix
@ -2474,7 +2474,7 @@ public class DecimalFormat extends NumberFormat {
boolean isExponent, boolean[] status) {
// process digits or Inf, find decimal position
status[STATUS_INFINITE] = false;
int intIndex = 0;
int intIndex = -1;
if (!isExponent && text.regionMatches(position, symbols.getInfinity(), 0,
symbols.getInfinity().length())) {
position += symbols.getInfinity().length();
@ -2570,6 +2570,10 @@ public class DecimalFormat extends NumberFormat {
// Cancel out backup setting (see grouping handler below)
backup = -1;
} else if (!isExponent && ch == decimal) {
if (isParseIntegerOnly() && startPos == position) {
// Parsing int only with no integer portion, fail
return new NumericPosition(-1, intIndex);
}
// Check grouping size on decimal separator
if (parseStrict && isGroupingViolation(position, prevSeparatorIndex)) {
return new NumericPosition(

@ -23,7 +23,7 @@
/*
* @test
* @bug 8327640 8331485 8333456
* @bug 8327640 8331485 8333456 8335668
* @summary Test suite for NumberFormat parsing when lenient.
* @run junit/othervm -Duser.language=en -Duser.country=US LenientParseTest
* @run junit/othervm -Duser.language=ja -Duser.country=JP LenientParseTest
@ -128,6 +128,28 @@ public class LenientParseTest {
dFmt.setParseIntegerOnly(false);
}
// 8335668: Parsing with integer only against String with no integer portion
// should fail, not return 0. Expected error index should be 0
@Test
public void integerParseOnlyFractionOnlyTest() {
var fmt = NumberFormat.getIntegerInstance();
failParse(fmt, localizeText("."), 0);
failParse(fmt, localizeText(".0"), 0);
failParse(fmt, localizeText(".55"), 0);
}
// 8335668: Parsing with integer only against String with no integer portion
// should fail, not return 0. Expected error index should be 0
@Test // Non-localized, run once
@EnabledIfSystemProperty(named = "user.language", matches = "en")
public void compactIntegerParseOnlyFractionOnlyTest() {
var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
fmt.setParseIntegerOnly(true);
failParse(fmt, ".K", 0);
failParse(fmt, ".0K", 0);
failParse(fmt, ".55K", 0);
}
@Test // Non-localized, only run once
@EnabledIfSystemProperty(named = "user.language", matches = "en")
public void badExponentParseNumberFormatTest() {
@ -313,7 +335,11 @@ public class LenientParseTest {
Arguments.of("10000", 10000d),
Arguments.of("100,000", 100000d),
Arguments.of("1,000,000", 1000000d),
Arguments.of("10,000,000", 10000000d))
Arguments.of("10,000,000", 10000000d),
// Smaller value cases (w/ decimal)
Arguments.of(".1", .1d),
Arguments.of("1.1", 1.1d),
Arguments.of("11.1", 11.1d))
.map(args -> Arguments.of(
localizeText(String.valueOf(args.get()[0])), args.get()[1]));
}

@ -23,7 +23,7 @@
/*
* @test
* @bug 8327640 8331485 8333755
* @bug 8327640 8331485 8333755 8335668
* @summary Test suite for NumberFormat parsing with strict leniency
* @run junit/othervm -Duser.language=en -Duser.country=US StrictParseTest
* @run junit/othervm -Duser.language=ja -Duser.country=JP StrictParseTest
@ -203,6 +203,28 @@ public class StrictParseTest {
}
}
// 8335668: Parsing with integer only against String with no integer portion
// should fail, not return 0. Expected error index should be 0
@Test
public void integerParseOnlyFractionOnlyTest() {
var fmt = NumberFormat.getIntegerInstance();
failParse(fmt, localizeText("."), 0);
failParse(fmt, localizeText(".0"), 0);
failParse(fmt, localizeText(".55"), 0);
}
// 8335668: Parsing with integer only against String with no integer portion
// should fail, not return 0. Expected error index should be 0
@Test // Non-localized, run once
@EnabledIfSystemProperty(named = "user.language", matches = "en")
public void compactIntegerParseOnlyFractionOnlyTest() {
var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
fmt.setParseIntegerOnly(true);
failParse(fmt, ".K", 0);
failParse(fmt, ".0K", 0);
failParse(fmt, ".55K", 0);
}
// 8333755: Parsing behavior should follow normal strict behavior
// when it comes to failures.
@ParameterizedTest
@ -426,8 +448,8 @@ public class StrictParseTest {
Arguments.of("1,234a", 5),
Arguments.of("1,.a", 2),
Arguments.of("1.a", 2),
Arguments.of(".22a", 3),
Arguments.of(".1a1", 2),
Arguments.of("1.22a", 4),
Arguments.of("1.1a1", 3),
Arguments.of("1,234,a", 5),
// Double decimal
Arguments.of("1,234..5", 5))
@ -453,7 +475,11 @@ public class StrictParseTest {
Arguments.of("10000", 10000d),
Arguments.of("100,000", 100000d),
Arguments.of("1,000,000", 1000000d),
Arguments.of("10,000,000", 10000000d))
Arguments.of("10,000,000", 10000000d),
// Smaller value cases (w/ decimal)
Arguments.of(".1", .1d),
Arguments.of("1.1", 1.1d),
Arguments.of("11.1", 11.1d))
.map(args -> Arguments.of(
localizeText(String.valueOf(args.get()[0])), args.get()[1]));
}