8165466: DecimalFormat percentage format can contain unexpected %
Reviewed-by: okutsu, peytoia
This commit is contained in:
parent
5e84d49af5
commit
f1f59c6623
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -968,7 +968,7 @@ public class DecimalFormat extends NumberFormat {
|
||||
* Decimal : min = 0. max = 3.
|
||||
*
|
||||
*/
|
||||
private void checkAndSetFastPathStatus() {
|
||||
private boolean checkAndSetFastPathStatus() {
|
||||
|
||||
boolean fastPathWasOn = isFastPath;
|
||||
|
||||
@ -998,12 +998,27 @@ public class DecimalFormat extends NumberFormat {
|
||||
} else
|
||||
isFastPath = false;
|
||||
|
||||
resetFastPathData(fastPathWasOn);
|
||||
fastPathCheckNeeded = false;
|
||||
|
||||
/*
|
||||
* Returns true after successfully checking the fast path condition and
|
||||
* setting the fast path data. The return value is used by the
|
||||
* fastFormat() method to decide whether to call the resetFastPathData
|
||||
* method to reinitialize fast path data or is it already initialized
|
||||
* in this method.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
private void resetFastPathData(boolean fastPathWasOn) {
|
||||
// Since some instance properties may have changed while still falling
|
||||
// in the fast-path case, we need to reinitialize fastPathData anyway.
|
||||
if (isFastPath) {
|
||||
// We need to instantiate fastPathData if not already done.
|
||||
if (fastPathData == null)
|
||||
if (fastPathData == null) {
|
||||
fastPathData = new FastPathData();
|
||||
}
|
||||
|
||||
// Sets up the locale specific constants used when formatting.
|
||||
// '0' is our default representation of zero.
|
||||
@ -1011,22 +1026,27 @@ public class DecimalFormat extends NumberFormat {
|
||||
fastPathData.groupingChar = symbols.getGroupingSeparator();
|
||||
|
||||
// Sets up fractional constants related to currency/decimal pattern.
|
||||
fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
|
||||
fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
|
||||
fastPathData.fractionalMaxIntBound = (isCurrencyFormat)
|
||||
? 99 : 999;
|
||||
fastPathData.fractionalScaleFactor = (isCurrencyFormat)
|
||||
? 100.0d : 1000.0d;
|
||||
|
||||
// Records the need for adding prefix or suffix
|
||||
fastPathData.positiveAffixesRequired =
|
||||
(positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
|
||||
fastPathData.negativeAffixesRequired =
|
||||
(negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
|
||||
fastPathData.positiveAffixesRequired
|
||||
= (positivePrefix.length() != 0)
|
||||
|| (positiveSuffix.length() != 0);
|
||||
fastPathData.negativeAffixesRequired
|
||||
= (negativePrefix.length() != 0)
|
||||
|| (negativeSuffix.length() != 0);
|
||||
|
||||
// Creates a cached char container for result, with max possible size.
|
||||
int maxNbIntegralDigits = 10;
|
||||
int maxNbGroups = 3;
|
||||
int containerSize =
|
||||
Math.max(positivePrefix.length(), negativePrefix.length()) +
|
||||
maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
|
||||
Math.max(positiveSuffix.length(), negativeSuffix.length());
|
||||
int containerSize
|
||||
= Math.max(positivePrefix.length(), negativePrefix.length())
|
||||
+ maxNbIntegralDigits + maxNbGroups + 1
|
||||
+ maximumFractionDigits
|
||||
+ Math.max(positiveSuffix.length(), negativeSuffix.length());
|
||||
|
||||
fastPathData.fastPathContainer = new char[containerSize];
|
||||
|
||||
@ -1038,17 +1058,18 @@ public class DecimalFormat extends NumberFormat {
|
||||
|
||||
// Sets up fixed index positions for integral and fractional digits.
|
||||
// Sets up decimal point in cached result container.
|
||||
int longestPrefixLength =
|
||||
Math.max(positivePrefix.length(), negativePrefix.length());
|
||||
int decimalPointIndex =
|
||||
maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
|
||||
int longestPrefixLength
|
||||
= Math.max(positivePrefix.length(),
|
||||
negativePrefix.length());
|
||||
int decimalPointIndex
|
||||
= maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
|
||||
|
||||
fastPathData.integralLastIndex = decimalPointIndex - 1;
|
||||
fastPathData.integralLastIndex = decimalPointIndex - 1;
|
||||
fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
|
||||
fastPathData.fastPathContainer[decimalPointIndex] =
|
||||
isCurrencyFormat ?
|
||||
symbols.getMonetaryDecimalSeparator() :
|
||||
symbols.getDecimalSeparator();
|
||||
fastPathData.fastPathContainer[decimalPointIndex]
|
||||
= isCurrencyFormat
|
||||
? symbols.getMonetaryDecimalSeparator()
|
||||
: symbols.getDecimalSeparator();
|
||||
|
||||
} else if (fastPathWasOn) {
|
||||
// Previous state was fast-path and is no more.
|
||||
@ -1059,8 +1080,6 @@ public class DecimalFormat extends NumberFormat {
|
||||
fastPathData.charsPositivePrefix = null;
|
||||
fastPathData.charsNegativePrefix = null;
|
||||
}
|
||||
|
||||
fastPathCheckNeeded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1554,9 +1573,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
* @return the formatted result for {@code d} as a string.
|
||||
*/
|
||||
String fastFormat(double d) {
|
||||
boolean isDataSet = false;
|
||||
// (Re-)Evaluates fast-path status if needed.
|
||||
if (fastPathCheckNeeded)
|
||||
checkAndSetFastPathStatus();
|
||||
if (fastPathCheckNeeded) {
|
||||
isDataSet = checkAndSetFastPathStatus();
|
||||
}
|
||||
|
||||
if (!isFastPath )
|
||||
// DecimalFormat instance is not in a fast-path state.
|
||||
@ -1580,9 +1601,21 @@ public class DecimalFormat extends NumberFormat {
|
||||
if (d > MAX_INT_AS_DOUBLE)
|
||||
// Filters out values that are outside expected fast-path range
|
||||
return null;
|
||||
else
|
||||
else {
|
||||
if (!isDataSet) {
|
||||
/*
|
||||
* If the fast path data is not set through
|
||||
* checkAndSetFastPathStatus() and fulfil the
|
||||
* fast path conditions then reset the data
|
||||
* directly through resetFastPathData()
|
||||
*/
|
||||
resetFastPathData(isFastPath);
|
||||
}
|
||||
fastDoubleFormat(d, negative);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Returns a new string from updated fastPathContainer.
|
||||
return new String(fastPathData.fastPathContainer,
|
||||
fastPathData.firstUsedIndex,
|
||||
|
95
jdk/test/java/text/Format/DecimalFormat/Bug8165466.java
Normal file
95
jdk/test/java/text/Format/DecimalFormat/Bug8165466.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
* @test
|
||||
* @bug 8165466
|
||||
* @summary Checks the subsequent function calls of the DecimalFormat.format()
|
||||
* method in which the minimumFractionDigit is set to 0 and one of
|
||||
* the format() call include formatting of the number with zero
|
||||
* fraction value e.g. 0.00, 9.00
|
||||
*/
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Bug8165466 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
DecimalFormat nf = (DecimalFormat) DecimalFormat
|
||||
.getPercentInstance(Locale.US);
|
||||
nf.setMaximumFractionDigits(3);
|
||||
nf.setMinimumFractionDigits(0);
|
||||
nf.setMultiplier(1);
|
||||
|
||||
double d = 0.005678;
|
||||
String result = nf.format(d);
|
||||
if (!result.equals("0.006%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 0.006%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
|
||||
d = 0.00;
|
||||
result = nf.format(d);
|
||||
if (!result.equals("0%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 0%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
|
||||
d = 0.005678;
|
||||
result = nf.format(d);
|
||||
if (!result.equals("0.006%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 0.006%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
|
||||
//checking with the non zero value
|
||||
d = 0.005678;
|
||||
result = nf.format(d);
|
||||
if (!result.equals("0.006%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 0.006%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
|
||||
d = 9.00;
|
||||
result = nf.format(d);
|
||||
if (!result.equals("9%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 9%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
|
||||
d = 0.005678;
|
||||
result = nf.format(d);
|
||||
if (!result.equals("0.006%")) {
|
||||
throw new RuntimeException("[Failed while formatting the double"
|
||||
+ " value: " + d + " Expected: 0.006%, Found: " + result
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user