8220224: With CLDR provider, NumberFormat.format could not handle locale with number extension correctly
Reviewed-by: darcy
This commit is contained in:
parent
954c66afed
commit
dc3c9c8439
src/java.base/share/classes/java/text
test/jdk/java/text/Format/NumberFormat
@ -836,7 +836,8 @@ public final class CompactNumberFormat extends NumberFormat {
|
||||
if (ch == QUOTE) {
|
||||
ch = pattern.charAt(index++);
|
||||
if (ch == MINUS_SIGN) {
|
||||
ch = symbols.getMinusSign();
|
||||
sb.append(symbols.getMinusSignText());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sb.append(ch);
|
||||
@ -859,11 +860,14 @@ public final class CompactNumberFormat extends NumberFormat {
|
||||
if (ch == QUOTE) {
|
||||
ch = pattern.charAt(index++);
|
||||
if (ch == MINUS_SIGN) {
|
||||
ch = symbols.getMinusSign();
|
||||
String minusText = symbols.getMinusSignText();
|
||||
FieldPosition fp = new FieldPosition(NumberFormat.Field.SIGN);
|
||||
fp.setBeginIndex(stringIndex);
|
||||
fp.setEndIndex(stringIndex + 1);
|
||||
fp.setEndIndex(stringIndex + minusText.length());
|
||||
positions.add(fp);
|
||||
stringIndex += minusText.length();
|
||||
affix.append(minusText);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
stringIndex++;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2019, 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
|
||||
@ -38,12 +38,14 @@
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.spi.DecimalFormatSymbolsProvider;
|
||||
import java.util.Currency;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import sun.util.locale.provider.CalendarDataUtility;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
@ -51,11 +53,11 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
|
||||
|
||||
/**
|
||||
* This class represents the set of symbols (such as the decimal separator,
|
||||
* the grouping separator, and so on) needed by <code>DecimalFormat</code>
|
||||
* to format numbers. <code>DecimalFormat</code> creates for itself an instance of
|
||||
* <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
|
||||
* of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
|
||||
* your <code>DecimalFormat</code> and modify it.
|
||||
* the grouping separator, and so on) needed by {@code DecimalFormat}
|
||||
* to format numbers. {@code DecimalFormat} creates for itself an instance of
|
||||
* {@code DecimalFormatSymbols} from its locale data. If you need to change any
|
||||
* of these symbols, you can get the {@code DecimalFormatSymbols} object from
|
||||
* your {@code DecimalFormat} and modify it.
|
||||
*
|
||||
* <p>If the locale contains "rg" (region override)
|
||||
* <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>,
|
||||
@ -107,7 +109,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* instead of the Latin numbering system.
|
||||
*
|
||||
* @param locale the desired locale
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @exception NullPointerException if {@code locale} is null
|
||||
*/
|
||||
public DecimalFormatSymbols( Locale locale ) {
|
||||
initialize( locale );
|
||||
@ -115,16 +117,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
|
||||
/**
|
||||
* Returns an array of all locales for which the
|
||||
* <code>getInstance</code> methods of this class can return
|
||||
* {@code getInstance} methods of this class can return
|
||||
* localized instances.
|
||||
* The returned array represents the union of locales supported by the Java
|
||||
* runtime and by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
|
||||
* implementations. It must contain at least a <code>Locale</code>
|
||||
* implementations. It must contain at least a {@code Locale}
|
||||
* instance equal to {@link java.util.Locale#US Locale.US}.
|
||||
*
|
||||
* @return an array of locales for which localized
|
||||
* <code>DecimalFormatSymbols</code> instances are available.
|
||||
* {@code DecimalFormatSymbols} instances are available.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
@ -134,8 +136,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DecimalFormatSymbols</code> instance for the default
|
||||
* locale. This method provides access to <code>DecimalFormatSymbols</code>
|
||||
* Gets the {@code DecimalFormatSymbols} instance for the default
|
||||
* locale. This method provides access to {@code DecimalFormatSymbols}
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider
|
||||
@ -145,7 +147,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
|
||||
* @see java.util.Locale#getDefault(java.util.Locale.Category)
|
||||
* @see java.util.Locale.Category#FORMAT
|
||||
* @return a <code>DecimalFormatSymbols</code> instance.
|
||||
* @return a {@code DecimalFormatSymbols} instance.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DecimalFormatSymbols getInstance() {
|
||||
@ -153,8 +155,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>DecimalFormatSymbols</code> instance for the specified
|
||||
* locale. This method provides access to <code>DecimalFormatSymbols</code>
|
||||
* Gets the {@code DecimalFormatSymbols} instance for the specified
|
||||
* locale. This method provides access to {@code DecimalFormatSymbols}
|
||||
* instances for locales supported by the Java runtime itself as well
|
||||
* as for those supported by installed
|
||||
* {@link java.text.spi.DecimalFormatSymbolsProvider
|
||||
@ -169,8 +171,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* instead of the Latin numbering system.
|
||||
*
|
||||
* @param locale the desired locale.
|
||||
* @return a <code>DecimalFormatSymbols</code> instance.
|
||||
* @exception NullPointerException if <code>locale</code> is null
|
||||
* @return a {@code DecimalFormatSymbols} instance.
|
||||
* @exception NullPointerException if {@code locale} is null
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final DecimalFormatSymbols getInstance(Locale locale) {
|
||||
@ -255,6 +257,41 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
*/
|
||||
public void setPerMill(char perMill) {
|
||||
this.perMill = perMill;
|
||||
this.perMillText = Character.toString(perMill);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string used for per mille sign. Different for Arabic, etc.
|
||||
*
|
||||
* @return the string used for per mille sign
|
||||
* @since 13
|
||||
*/
|
||||
String getPerMillText() {
|
||||
return perMillText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used for per mille sign. Different for Arabic, etc.
|
||||
*
|
||||
* Setting the {@code perMillText} affects the return value of
|
||||
* {@link #getPerMill()}, in which the first non-format character of
|
||||
* {@code perMillText} is returned.
|
||||
*
|
||||
* @param perMillText the string used for per mille sign
|
||||
* @throws NullPointerException if {@code perMillText} is null
|
||||
* @throws IllegalArgumentException if {@code perMillText} is an empty string
|
||||
* @see #getPerMill()
|
||||
* @see #getPerMillText()
|
||||
* @since 13
|
||||
*/
|
||||
void setPerMillText(String perMillText) {
|
||||
Objects.requireNonNull(perMillText);
|
||||
if (perMillText.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty argument string");
|
||||
}
|
||||
|
||||
this.perMillText = perMillText;
|
||||
this.perMill = findNonFormatChar(perMillText, '\u2030');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -273,6 +310,41 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
*/
|
||||
public void setPercent(char percent) {
|
||||
this.percent = percent;
|
||||
this.percentText = Character.toString(percent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string used for percent sign. Different for Arabic, etc.
|
||||
*
|
||||
* @return the string used for percent sign
|
||||
* @since 13
|
||||
*/
|
||||
String getPercentText() {
|
||||
return percentText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used for percent sign. Different for Arabic, etc.
|
||||
*
|
||||
* Setting the {@code percentText} affects the return value of
|
||||
* {@link #getPercent()}, in which the first non-format character of
|
||||
* {@code percentText} is returned.
|
||||
*
|
||||
* @param percentText the string used for percent sign
|
||||
* @throws NullPointerException if {@code percentText} is null
|
||||
* @throws IllegalArgumentException if {@code percentText} is an empty string
|
||||
* @see #getPercent()
|
||||
* @see #getPercentText()
|
||||
* @since 13
|
||||
*/
|
||||
void setPercentText(String percentText) {
|
||||
Objects.requireNonNull(percentText);
|
||||
if (percentText.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty argument string");
|
||||
}
|
||||
|
||||
this.percentText = percentText;
|
||||
this.percent = findNonFormatChar(percentText, '%');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,6 +445,46 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
*/
|
||||
public void setMinusSign(char minusSign) {
|
||||
this.minusSign = minusSign;
|
||||
this.minusSignText = Character.toString(minusSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string used to represent minus sign. If no explicit
|
||||
* negative format is specified, one is formed by prefixing
|
||||
* minusSignText to the positive format.
|
||||
*
|
||||
* @return the string representing minus sign
|
||||
* @since 13
|
||||
*/
|
||||
String getMinusSignText() {
|
||||
return minusSignText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string used to represent minus sign. If no explicit
|
||||
* negative format is specified, one is formed by prefixing
|
||||
* minusSignText to the positive format.
|
||||
*
|
||||
* Setting the {@code minusSignText} affects the return value of
|
||||
* {@link #getMinusSign()}, in which the first non-format character of
|
||||
* {@code minusSignText} is returned.
|
||||
*
|
||||
* @param minusSignText the character representing minus sign
|
||||
* @throws NullPointerException if {@code minusSignText} is null
|
||||
* @throws IllegalArgumentException if {@code minusSignText} is an
|
||||
* empty string
|
||||
* @see #getMinusSign()
|
||||
* @see #getMinusSignText()
|
||||
* @since 13
|
||||
*/
|
||||
void setMinusSignText(String minusSignText) {
|
||||
Objects.requireNonNull(minusSignText);
|
||||
if (minusSignText.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty argument string");
|
||||
}
|
||||
|
||||
this.minusSignText = minusSignText;
|
||||
this.minusSign = findNonFormatChar(minusSignText, '-');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -464,7 +576,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* symbol attribute to the currency's ISO 4217 currency code.
|
||||
*
|
||||
* @param currency the new currency to be used
|
||||
* @exception NullPointerException if <code>currency</code> is null
|
||||
* @exception NullPointerException if {@code currency} is null
|
||||
* @since 1.4
|
||||
* @see #setCurrencySymbol
|
||||
* @see #setInternationalCurrencySymbol
|
||||
@ -540,7 +652,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
|
||||
*
|
||||
* @param exp the exponent separator string
|
||||
* @exception NullPointerException if <code>exp</code> is null
|
||||
* @exception NullPointerException if {@code exp} is null
|
||||
* @see #getExponentSeparator()
|
||||
* @since 1.6
|
||||
*/
|
||||
@ -583,9 +695,12 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
groupingSeparator == other.groupingSeparator &&
|
||||
decimalSeparator == other.decimalSeparator &&
|
||||
percent == other.percent &&
|
||||
percentText.equals(other.percentText) &&
|
||||
perMill == other.perMill &&
|
||||
perMillText.equals(other.perMillText) &&
|
||||
digit == other.digit &&
|
||||
minusSign == other.minusSign &&
|
||||
minusSignText.equals(other.minusSignText) &&
|
||||
patternSeparator == other.patternSeparator &&
|
||||
infinity.equals(other.infinity) &&
|
||||
NaN.equals(other.NaN) &&
|
||||
@ -631,13 +746,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
decimalSeparator = numberElements[0].charAt(0);
|
||||
groupingSeparator = numberElements[1].charAt(0);
|
||||
patternSeparator = numberElements[2].charAt(0);
|
||||
percent = numberElements[3].charAt(0);
|
||||
percentText = numberElements[3];
|
||||
percent = findNonFormatChar(percentText, '%');
|
||||
zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
|
||||
digit = numberElements[5].charAt(0);
|
||||
minusSign = numberElements[6].charAt(0);
|
||||
minusSignText = numberElements[6];
|
||||
minusSign = findNonFormatChar(minusSignText, '-');
|
||||
exponential = numberElements[7].charAt(0);
|
||||
exponentialSeparator = numberElements[7]; //string representation new since 1.6
|
||||
perMill = numberElements[8].charAt(0);
|
||||
perMillText = numberElements[8];
|
||||
perMill = findNonFormatChar(perMillText, '\u2030');
|
||||
infinity = numberElements[9];
|
||||
NaN = numberElements[10];
|
||||
|
||||
@ -651,6 +769,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
monetarySeparator = decimalSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains non-format single character from String
|
||||
*/
|
||||
private char findNonFormatChar(String src, char defChar) {
|
||||
return (char)src.chars()
|
||||
.filter(c -> Character.getType(c) != Character.FORMAT)
|
||||
.findFirst()
|
||||
.orElse(defChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy initialization for currency related fields
|
||||
*/
|
||||
@ -704,18 +832,24 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
/**
|
||||
* Reads the default serializable fields, provides default values for objects
|
||||
* in older serial versions, and initializes non-serializable fields.
|
||||
* If <code>serialVersionOnStream</code>
|
||||
* is less than 1, initializes <code>monetarySeparator</code> to be
|
||||
* the same as <code>decimalSeparator</code> and <code>exponential</code>
|
||||
* If {@code serialVersionOnStream}
|
||||
* is less than 1, initializes {@code monetarySeparator} to be
|
||||
* the same as {@code decimalSeparator} and {@code exponential}
|
||||
* to be 'E'.
|
||||
* If <code>serialVersionOnStream</code> is less than 2,
|
||||
* initializes <code>locale</code>to the root locale, and initializes
|
||||
* If <code>serialVersionOnStream</code> is less than 3, it initializes
|
||||
* <code>exponentialSeparator</code> using <code>exponential</code>.
|
||||
* Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
|
||||
* If {@code serialVersionOnStream} is less than 2,
|
||||
* initializes {@code locale}to the root locale, and initializes
|
||||
* If {@code serialVersionOnStream} is less than 3, it initializes
|
||||
* {@code exponentialSeparator} using {@code exponential}.
|
||||
* If {@code serialVersionOnStream} is less than 4, it initializes
|
||||
* {@code perMillText}, {@code percentText}, and
|
||||
* {@code minusSignText} using {@code perMill}, {@code percent}, and
|
||||
* {@code minusSign} respectively.
|
||||
* Sets {@code serialVersionOnStream} back to the maximum allowed value so that
|
||||
* default serialization will work properly if this object is streamed out again.
|
||||
* Initializes the currency from the intlCurrencySymbol field.
|
||||
*
|
||||
* @throws InvalidObjectException if {@code char} and {@code String}
|
||||
* representations of either percent, per mille, and/or minus sign disagree.
|
||||
* @since 1.1.6
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
@ -735,6 +869,23 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
// didn't have exponentialSeparator. Create one using exponential
|
||||
exponentialSeparator = Character.toString(exponential);
|
||||
}
|
||||
if (serialVersionOnStream < 4) {
|
||||
// didn't have perMillText, percentText, and minusSignText.
|
||||
// Create one using corresponding char variations.
|
||||
perMillText = Character.toString(perMill);
|
||||
percentText = Character.toString(percent);
|
||||
minusSignText = Character.toString(minusSign);
|
||||
} else {
|
||||
// Check whether char and text fields agree
|
||||
if (findNonFormatChar(perMillText, '\uFFFF') != perMill ||
|
||||
findNonFormatChar(percentText, '\uFFFF') != percent ||
|
||||
findNonFormatChar(minusSignText, '\uFFFF') != minusSign) {
|
||||
throw new InvalidObjectException(
|
||||
"'char' and 'String' representations of either percent, " +
|
||||
"per mille, and/or minus sign disagree.");
|
||||
}
|
||||
}
|
||||
|
||||
serialVersionOnStream = currentSerialVersion;
|
||||
|
||||
if (intlCurrencySymbol != null) {
|
||||
@ -862,8 +1013,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* The string used to separate the mantissa from the exponent.
|
||||
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
|
||||
* <p>
|
||||
* If both <code>exponential</code> and <code>exponentialSeparator</code>
|
||||
* exist, this <code>exponentialSeparator</code> has the precedence.
|
||||
* If both {@code exponential} and {@code exponentialSeparator}
|
||||
* exist, this {@code exponentialSeparator} has the precedence.
|
||||
*
|
||||
* @serial
|
||||
* @since 1.6
|
||||
@ -878,6 +1029,39 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
/**
|
||||
* String representation of per mille sign, which may include
|
||||
* formatting characters, such as BiDi control characters.
|
||||
* The first non-format character of this string is the same as
|
||||
* {@code perMill}.
|
||||
*
|
||||
* @serial
|
||||
* @since 13
|
||||
*/
|
||||
private String perMillText;
|
||||
|
||||
/**
|
||||
* String representation of percent sign, which may include
|
||||
* formatting characters, such as BiDi control characters.
|
||||
* The first non-format character of this string is the same as
|
||||
* {@code percent}.
|
||||
*
|
||||
* @serial
|
||||
* @since 13
|
||||
*/
|
||||
private String percentText;
|
||||
|
||||
/**
|
||||
* String representation of minus sign, which may include
|
||||
* formatting characters, such as BiDi control characters.
|
||||
* The first non-format character of this string is the same as
|
||||
* {@code minusSign}.
|
||||
*
|
||||
* @serial
|
||||
* @since 13
|
||||
*/
|
||||
private String minusSignText;
|
||||
|
||||
// currency; only the ISO code is serialized.
|
||||
private transient Currency currency;
|
||||
private transient volatile boolean currencyInitialized;
|
||||
@ -891,23 +1075,28 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
// monetarySeparator and exponential.
|
||||
// - 2 for version from J2SE 1.4, which includes locale field.
|
||||
// - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
|
||||
private static final int currentSerialVersion = 3;
|
||||
// - 4 for version from Java SE 13, which includes perMillText, percentText,
|
||||
// and minusSignText field.
|
||||
private static final int currentSerialVersion = 4;
|
||||
|
||||
/**
|
||||
* Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
|
||||
* Describes the version of {@code DecimalFormatSymbols} present on the stream.
|
||||
* Possible values are:
|
||||
* <ul>
|
||||
* <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
|
||||
*
|
||||
* <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
|
||||
* two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
|
||||
* two new fields: {@code monetarySeparator} and {@code exponential}.
|
||||
* <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
|
||||
* new <code>locale</code> field.
|
||||
* new {@code locale} field.
|
||||
* <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
|
||||
* new <code>exponentialSeparator</code> field.
|
||||
* new {@code exponentialSeparator} field.
|
||||
* <li><b>4</b>: Versions written by Java SE 13 or later, which include
|
||||
* new {@code perMillText}, {@code percentText}, and
|
||||
* {@code minusSignText} field.
|
||||
* </ul>
|
||||
* When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
|
||||
* (corresponding to the highest allowable <code>serialVersionOnStream</code>)
|
||||
* When streaming out a {@code DecimalFormatSymbols}, the most recent format
|
||||
* (corresponding to the highest allowable {@code serialVersionOnStream})
|
||||
* is always written.
|
||||
*
|
||||
* @serial
|
||||
|
139
test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java
Normal file
139
test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 8220309
|
||||
* @library /java/text/testlib
|
||||
* @summary Test String representation of MinusSign/Percent/PerMill symbols.
|
||||
* This test assumes CLDR has numbering systems for "arab" and
|
||||
* "arabext", and their minus/percent representations include
|
||||
* BiDi formatting control characters.
|
||||
* @run testng/othervm DFSMinusPerCentMill
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class DFSMinusPerCentMill {
|
||||
private enum Type {
|
||||
NUMBER, PERCENT, CURRENCY, INTEGER, COMPACT, PERMILL
|
||||
}
|
||||
|
||||
private static final Locale US_ARAB = Locale.forLanguageTag("en-US-u-nu-arab");
|
||||
private static final Locale US_ARABEXT = Locale.forLanguageTag("en-US-u-nu-arabext");
|
||||
private static final double SRC_NUM = -1234.56;
|
||||
|
||||
@DataProvider
|
||||
Object[][] formatData() {
|
||||
return new Object[][] {
|
||||
// Locale, FormatStyle, expected format, expected single char symbol
|
||||
{US_ARAB, Type.NUMBER, "\u061c-\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
|
||||
{US_ARAB, Type.PERCENT, "\u061c-\u0661\u0662\u0663\u066c\u0664\u0665\u0666\u066a\u061c"},
|
||||
{US_ARAB, Type.CURRENCY, "\u061c-$\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
|
||||
{US_ARAB, Type.INTEGER, "\u061c-\u0661\u066c\u0662\u0663\u0665"},
|
||||
{US_ARAB, Type.COMPACT, "\u061c-\u0661K"},
|
||||
{US_ARAB, Type.PERMILL, "\u061c-\u0661\u0662\u0663\u0664\u0665\u0666\u0660\u0609"},
|
||||
|
||||
{US_ARABEXT, Type.NUMBER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
|
||||
{US_ARABEXT, Type.PERCENT, "\u200e-\u200e\u06f1\u06f2\u06f3\u066c\u06f4\u06f5\u06f6\u066a"},
|
||||
{US_ARABEXT, Type.CURRENCY, "\u200e-\u200e$\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
|
||||
{US_ARABEXT, Type.INTEGER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f5"},
|
||||
{US_ARABEXT, Type.COMPACT, "\u200e-\u200e\u06f1K"},
|
||||
{US_ARABEXT, Type.PERMILL, "\u200e-\u200e\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f0\u0609"},
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
Object[][] charSymbols() {
|
||||
return new Object[][]{
|
||||
// Locale, percent, per mille, minus sign
|
||||
{US_ARAB, '\u066a', '\u0609', '-'},
|
||||
{US_ARABEXT, '\u066a', '\u0609', '-'},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider="formatData")
|
||||
public void testFormatData(Locale l, Type style, String expected) {
|
||||
NumberFormat nf = null;
|
||||
switch (style) {
|
||||
case NUMBER:
|
||||
nf = NumberFormat.getNumberInstance(l);
|
||||
break;
|
||||
case PERCENT:
|
||||
nf = NumberFormat.getPercentInstance(l);
|
||||
break;
|
||||
case CURRENCY:
|
||||
nf = NumberFormat.getCurrencyInstance(l);
|
||||
break;
|
||||
case INTEGER:
|
||||
nf = NumberFormat.getIntegerInstance(l);
|
||||
break;
|
||||
case COMPACT:
|
||||
nf = NumberFormat.getCompactNumberInstance(l, NumberFormat.Style.SHORT);
|
||||
break;
|
||||
case PERMILL:
|
||||
nf = new DecimalFormat("#.#\u2030", DecimalFormatSymbols.getInstance(l));
|
||||
break;
|
||||
}
|
||||
|
||||
assertEquals(nf.format(SRC_NUM), expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="charSymbols")
|
||||
public void testCharSymbols(Locale l, char percent, char permill, char minus) {
|
||||
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
|
||||
assertEquals(dfs.getPercent(), percent);
|
||||
assertEquals(dfs.getPerMill(), permill);
|
||||
assertEquals(dfs.getMinusSign(), minus);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws Exception {
|
||||
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(bos).writeObject(dfs);
|
||||
DecimalFormatSymbols dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
|
||||
new ByteArrayInputStream(bos.toByteArray())
|
||||
).readObject();
|
||||
|
||||
assertEquals(dfs, dfsSerialized);
|
||||
|
||||
// set minus/percent/permille
|
||||
dfs.setMinusSign('a');
|
||||
dfs.setPercent('b');
|
||||
dfs.setPerMill('c');
|
||||
bos = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(bos).writeObject(dfs);
|
||||
dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
|
||||
new ByteArrayInputStream(bos.toByteArray())
|
||||
).readObject();
|
||||
|
||||
assertEquals(dfs, dfsSerialized);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user