ICU-13177 Pointing DecimalFormat.java and CompactDecimalFormat.java at the new API. All tests are passing.

X-SVN-Rev: 40313
This commit is contained in:
Shane Carr 2017-08-04 22:43:34 +00:00
parent 8cf6752ecb
commit ca30fb66ec
24 changed files with 467 additions and 742 deletions

View File

@ -259,8 +259,8 @@ $**####,##0 1234 $***1\u00a0234 K
// In J ICU adds padding as if 'EUR' is only 2 chars (2 * 0xa4)
\u00a4\u00a4 **####0.00 433.0 EUR *433,00 JK
// In J ICU adds padding as if 'EUR' is only 2 chars (2 * 0xa4)
// S fails this one because the test code bypasses CurrencyUsage
\u00a4\u00a4 **#######0 433.0 EUR *433,00 JKS
// S and Q fail this one because the test code bypasses CurrencyUsage
\u00a4\u00a4 **#######0 433.0 EUR *433,00 JKSQ
test padding and currencies
begin
@ -338,8 +338,8 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
// JDK gives E0 instead of allowing for unlimited precision
// S obeys the maximum integer digits and returns .299792458E9
0 0 0 0 2.99792458E8 KS
// JDK and S give .299792E9
0 1 0 5 2.9979E8 KS
// JDK and S give .299792E9; Q gives 2.99792E8
0 1 0 5 2.9979E8 KSQ
// JDK gives 300E6
0 3 0 0 299.792458E6 K
// JDK gives 299.8E6 (maybe maxInt + maxFrac instead of minInt + maxFrac)?
@ -356,12 +356,13 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
// JDK gives E0
// S obeys the maximum integer digits
0 0 1 0 2.99792458E8 KS
// JDK gives .2998E9
0 0 0 4 2.998E8 KS
// JDK and S give .2998E9
0 0 0 4 2.998E8 KSQ
// S correctly formats this as 29.979246E7.
// JDK uses 8 + 6 for significant digits instead of 2 + 6
// J and C return 2.9979246E8.
2 8 1 6 29.979246E7 CJK
// TODO: Merge trunk
2 8 1 6 29.979246E7 CJKQ
// Treat max int digits > 8 as being the same as min int digits.
// This behavior is not spelled out in the specification.
// JDK fails here because it tries to use 9 + 6 = 15 sig digits.
@ -405,12 +406,12 @@ begin
format maxIntegerDigits output breaks
123 1 3
0 0 0
// S ignores max integer if it is less than zero and prints "123"
123 -2147483648 0 S
// S and Q ignore max integer if it is less than zero and prints "123"
123 -2147483648 0 SQ
12345 1 5
12345 -2147483648 0 S
12345 -2147483648 0 SQ
5.3 1 5.3
5.3 -2147483648 .3 S
5.3 -2147483648 .3 SQ
test patterns with zero
set locale en
@ -489,8 +490,9 @@ output grouping breaks grouping2 minGroupingDigits
1,2345,6789 4
1,23,45,6789 4 K 2
1,23,45,6789 4 K 2 2
// Q only supports minGrouping<=2
123,456789 6 6 3
123456789 6 JK 6 4
123456789 6 JKQ 6 4
test multiplier setters
set locale en_US
@ -498,8 +500,10 @@ begin
format multiplier output breaks
23 -12 -276
23 -1 -23
// ICU4J and JDK throw exception on zero multiplier. ICU4C does not.
23 0 23 JKS
// ICU4J and JDK throw exception on zero multiplier.
// ICU4C and S print 23.
// Q multiplies by zero and prints 0.
23 0 0 CJKS
23 1 23
23 12 276
-23 12 -276
@ -513,8 +517,9 @@ begin
format output breaks
-0.35 -0.25 K
0.35 0.25 K
0.39 0.5 K
0.62 0.5 K
// Q doesn't support mixing minFrac with roundingIncrement (prints 0.50).
0.39 0.5 KQ
0.62 0.5 KQ
0.63 0.75 K
test padding setters
@ -539,20 +544,19 @@ output breaks useScientific
test rounding mode setters
set locale en_US
set pattern 0.#
set roundingIncrement 0.5
set pattern 0.5
begin
format roundingMode output breaks
1.24 halfUp 1 K
1.24 halfUp 1.0 K
1.25 halfUp 1.5 K
1.25 halfDown 1 K
1.25 halfDown 1.0 K
1.26 halfDown 1.5 K
1.25 halfEven 1 K
1.25 halfEven 1.0 K
-1.01 up -1.5 K
-1.49 down -1 K
-1.49 down -1.0 K
1.01 up 1.5 K
1.49 down 1 K
-1.01 ceiling -1
1.49 down 1.0 K
-1.01 ceiling -1.0
-1.49 floor -1.5
test currency usage setters
@ -584,7 +588,7 @@ set locale en
set currency USD
begin
pattern format output breaks
# 123 123 S
# 123 123 SQ
// Currency rounding should always override the pattern.
// K prints the currency in ISO format for some reason.
\u00a4# 123 $123.00 K
@ -659,7 +663,8 @@ begin
format output breaks
Inf [\u221e]
-Inf (\u221e) K
NaN NaN K
// Q prints the affixes
NaN NaN KQ
test nan and infinity with multiplication
set locale en
@ -680,10 +685,11 @@ Inf beforePrefix $$$\u221e$ K
Inf afterPrefix $$$ \u221e$ K
Inf beforeSuffix $$$\u221e $ K
Inf afterSuffix $$$\u221e$ K
NaN beforePrefix NaN K
NaN afterPrefix NaN K
NaN beforeSuffix NaN K
NaN afterSuffix NaN K
// Q gets $$$NaN$
NaN beforePrefix NaN KQ
NaN afterPrefix NaN KQ
NaN beforeSuffix NaN KQ
NaN afterSuffix NaN KQ
test apply formerly localized patterns
begin
@ -1540,8 +1546,9 @@ set maxSigDigits 2
begin
format output breaks
// C and J get "1"
// Q gets "1.0"
// K gets "1.1" (??)
0.975 0.98 CJK
0.975 0.98 CJKQ
test lenient parse currency match
// This test is for #13112

View File

@ -222,6 +222,13 @@ public class AffixPatternUtils {
return output.length() - startLength;
}
/** Version of {@link #escape} that returns a String. */
public static String escape(CharSequence input) {
StringBuilder sb = new StringBuilder();
escape(input, sb);
return sb.toString();
}
/**
* Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", and ""
* with their localized equivalents. Replaces "¤", "¤¤", and "¤¤¤" with the three argument

View File

@ -184,6 +184,9 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
@Override
public void multiplyBy(BigDecimal multiplicand) {
if (isInfinite() || isZero() || isNaN()) {
return;
}
BigDecimal temp = toBigDecimal();
temp = temp.multiply(multiplicand);
setToBigDecimal(temp);
@ -519,7 +522,7 @@ public abstract class FormatQuantityBCD implements FormatQuantity {
* @param n The value to consume.
*/
@Override
public void setToBigDecimal(BigDecimal n) {
public void setToBigDecimal(BigDecimal n) {
setBcdToZero();
flags = 0;
if (n.signum() == -1) {

View File

@ -46,6 +46,9 @@ public interface Modifier {
* Gets the prefix string associated with this modifier, defined as the string that will be
* inserted at leftIndex when {@link #apply} is called.
*
* <p>TODO: Change this to appendPrefixTo(), or remove it entirely and do something different at
* the call sites.
*
* @return The prefix string. Will not be null.
*/
public String getPrefix();
@ -54,6 +57,9 @@ public interface Modifier {
* Gets the prefix string associated with this modifier, defined as the string that will be
* inserted at rightIndex when {@link #apply} is called.
*
* <p>TODO: Change this to appendPrefixTo(), or remove it entirely and do something different at
* the call sites.
*
* @return The suffix string. Will not be null.
*/
public String getSuffix();
@ -102,8 +108,8 @@ public interface Modifier {
/**
* A starter implementation with defaults for some of the basic methods.
*
* <p>Implements {@link PositiveNegativeModifier} only so that instances of this class can be used when
* a {@link PositiveNegativeModifier} is required.
* <p>Implements {@link PositiveNegativeModifier} only so that instances of this class can be used
* when a {@link PositiveNegativeModifier} is required.
*/
public abstract static class BaseModifier extends Format.BeforeFormat
implements Modifier, PositiveNegativeModifier {

View File

@ -8,6 +8,8 @@ import com.ibm.icu.impl.number.formatters.PaddingFormat;
import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
import com.ibm.icu.text.DecimalFormatSymbols;
import newapi.impl.AffixPatternProvider;
/**
* Handles parsing and creation of the compact pattern string representation of a decimal format.
*/
@ -507,7 +509,8 @@ public class PatternString {
if (!ignoreRounding) {
properties.setMinimumFractionDigits(minFrac);
properties.setMaximumFractionDigits(positive.maximumFractionDigits);
properties.setRoundingIncrement(positive.rounding.toBigDecimal());
properties.setRoundingIncrement(
positive.rounding.toBigDecimal().setScale(positive.minimumFractionDigits));
} else {
properties.setMinimumFractionDigits(Properties.DEFAULT_MINIMUM_FRACTION_DIGITS);
properties.setMaximumFractionDigits(Properties.DEFAULT_MAXIMUM_FRACTION_DIGITS);
@ -557,8 +560,8 @@ public class PatternString {
}
// Compute the affix patterns (required for both padding and affixes)
String posPrefix = ppr.getString(LdmlPatternInfo.PatternParseResult.POS_PREFIX);
String posSuffix = ppr.getString(LdmlPatternInfo.PatternParseResult.POS_SUFFIX);
String posPrefix = ppr.getString(AffixPatternProvider.Flags.PREFIX);
String posSuffix = ppr.getString(0);
// Padding settings
if (positive.paddingEndpoints != 0) {
@ -568,7 +571,7 @@ public class PatternString {
+ AffixPatternUtils.unescapedLength(posPrefix)
+ AffixPatternUtils.unescapedLength(posSuffix);
properties.setFormatWidth(paddingWidth);
String rawPaddingString = ppr.getString(LdmlPatternInfo.PatternParseResult.POS_PADDING);
String rawPaddingString = ppr.getString(AffixPatternProvider.Flags.PADDING);
if (rawPaddingString.length() == 1) {
properties.setPadString(rawPaddingString);
} else if (rawPaddingString.length() == 2) {
@ -594,8 +597,11 @@ public class PatternString {
properties.setPositivePrefixPattern(posPrefix);
properties.setPositiveSuffixPattern(posSuffix);
if (negative != null) {
properties.setNegativePrefixPattern(ppr.getString(LdmlPatternInfo.PatternParseResult.NEG_PREFIX));
properties.setNegativeSuffixPattern(ppr.getString(LdmlPatternInfo.PatternParseResult.NEG_SUFFIX));
properties.setNegativePrefixPattern(
ppr.getString(
AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN | AffixPatternProvider.Flags.PREFIX));
properties.setNegativeSuffixPattern(
ppr.getString(AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN));
} else {
properties.setNegativePrefixPattern(null);
properties.setNegativeSuffixPattern(null);

View File

@ -32,7 +32,6 @@ import com.ibm.icu.impl.number.rounders.MagnitudeRounder;
import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.util.Currency;
@ -121,7 +120,6 @@ public class Properties
private transient RoundingMode roundingMode;
private transient int secondaryGroupingSize;
private transient boolean signAlwaysShown;
private transient SignificantDigitsMode significantDigitsMode;
/*--------------------------------------------------------------------------------------------+/
/| IMPORTANT! |/
@ -182,7 +180,6 @@ public class Properties
roundingMode = DEFAULT_ROUNDING_MODE;
secondaryGroupingSize = DEFAULT_SECONDARY_GROUPING_SIZE;
signAlwaysShown = DEFAULT_SIGN_ALWAYS_SHOWN;
significantDigitsMode = DEFAULT_SIGNIFICANT_DIGITS_MODE;
return this;
}
@ -232,7 +229,6 @@ public class Properties
roundingMode = other.roundingMode;
secondaryGroupingSize = other.secondaryGroupingSize;
signAlwaysShown = other.signAlwaysShown;
significantDigitsMode = other.significantDigitsMode;
return this;
}
@ -283,7 +279,6 @@ public class Properties
eq = eq && _equalsHelper(roundingMode, other.roundingMode);
eq = eq && _equalsHelper(secondaryGroupingSize, other.secondaryGroupingSize);
eq = eq && _equalsHelper(signAlwaysShown, other.signAlwaysShown);
eq = eq && _equalsHelper(significantDigitsMode, other.significantDigitsMode);
return eq;
}
@ -348,7 +343,6 @@ public class Properties
hashCode ^= _hashCodeHelper(roundingMode);
hashCode ^= _hashCodeHelper(secondaryGroupingSize);
hashCode ^= _hashCodeHelper(signAlwaysShown);
hashCode ^= _hashCodeHelper(significantDigitsMode);
return hashCode;
}
@ -627,11 +621,6 @@ public class Properties
return signAlwaysShown;
}
@Override
public SignificantDigitsMode getSignificantDigitsMode() {
return significantDigitsMode;
}
@Override
public int hashCode() {
return _hashCode();
@ -960,12 +949,6 @@ public class Properties
return this;
}
@Override
public Properties setSignificantDigitsMode(SignificantDigitsMode significantDigitsMode) {
this.significantDigitsMode = significantDigitsMode;
return this;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();

View File

@ -24,7 +24,6 @@ import com.ibm.icu.impl.number.modifiers.PositiveNegativeAffixModifier;
import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CompactDecimalFormat.CompactType;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.NumberingSystem;
@ -104,8 +103,6 @@ public class CompactDecimalFormat extends Format.BeforeFormat {
private static final int DEFAULT_MIN_SIG = 1;
private static final int DEFAULT_MAX_SIG = 2;
private static final SignificantDigitsMode DEFAULT_SIG_MODE =
SignificantDigitsMode.OVERRIDE_MAXIMUM_FRACTION;
private static final ThreadLocal<Properties> threadLocalProperties =
new ThreadLocal<Properties>() {
@ -127,12 +124,10 @@ public class CompactDecimalFormat extends Format.BeforeFormat {
if (rounder == null) {
int _minSig = properties.getMinimumSignificantDigits();
int _maxSig = properties.getMaximumSignificantDigits();
SignificantDigitsMode _mode = properties.getSignificantDigitsMode();
Properties rprops = threadLocalProperties.get().clear();
// Settings needing possible override:
rprops.setMinimumSignificantDigits(_minSig > 0 ? _minSig : DEFAULT_MIN_SIG);
rprops.setMaximumSignificantDigits(_maxSig > 0 ? _maxSig : DEFAULT_MAX_SIG);
rprops.setSignificantDigitsMode(_mode != null ? _mode : DEFAULT_SIG_MODE);
// TODO: Should copyFrom() be used instead? It requires a cast.
// Settings to copy verbatim:
rprops.setRoundingMode(properties.getRoundingMode());

View File

@ -17,16 +17,36 @@ public class SimpleModifier extends Modifier.BaseModifier {
private final Field field;
private final boolean strong;
private final int prefixLength;
private final int suffixOffset;
private final int suffixLength;
private static final int ARG_NUM_LIMIT = 0x100;
/** Creates a modifier that uses the SimpleFormatter string formats. */
public SimpleModifier(String compiledPattern, Field field, boolean strong) {
this.compiledPattern = (compiledPattern == null) ? "\u0001\u0000" : compiledPattern;
this.field = field;
this.strong = strong;
assert SimpleFormatterImpl.getArgumentLimit(compiledPattern) == 1;
if (compiledPattern.charAt(1) != '\u0000') {
prefixLength = compiledPattern.charAt(1) - ARG_NUM_LIMIT;
suffixOffset = 3 + prefixLength;
} else {
prefixLength = 0;
suffixOffset = 2;
}
if (3 + prefixLength < compiledPattern.length()) {
suffixLength = compiledPattern.charAt(suffixOffset) - ARG_NUM_LIMIT;
} else {
suffixLength = 0;
}
}
@Override
public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
return formatAsPrefixSuffix(compiledPattern, output, leftIndex, rightIndex, field);
return formatAsPrefixSuffix(output, leftIndex, rightIndex, field);
}
@Override
@ -36,14 +56,18 @@ public class SimpleModifier extends Modifier.BaseModifier {
@Override
public String getPrefix() {
// TODO: Implement this when MeasureFormat is ready.
throw new UnsupportedOperationException();
if (prefixLength == 0) {
return "";
}
return compiledPattern.substring(2, 2 + prefixLength);
}
@Override
public String getSuffix() {
// TODO: Implement this when MeasureFormat is ready.
throw new UnsupportedOperationException();
if (suffixLength == 0) {
return "";
}
return compiledPattern.substring(1 + suffixOffset, 1 + suffixOffset + suffixLength);
}
/**
@ -57,38 +81,26 @@ public class SimpleModifier extends Modifier.BaseModifier {
*
* <p>This is well-defined only for patterns with exactly one argument.
*
* @param compiledPattern Compiled form of a pattern string.
* @param result The StringBuilder containing the value argument.
* @param startIndex The left index of the value within the string builder.
* @param endIndex The right index of the value within the string builder.
* @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
*/
public static int formatAsPrefixSuffix(
String compiledPattern,
NumberStringBuilder result,
int startIndex,
int endIndex,
Field field) {
public int formatAsPrefixSuffix(
NumberStringBuilder result, int startIndex, int endIndex, Field field) {
assert SimpleFormatterImpl.getArgumentLimit(compiledPattern) == 1;
int ARG_NUM_LIMIT = 0x100;
int length = 0, offset = 2;
if (compiledPattern.charAt(1) != '\u0000') {
int prefixLength = compiledPattern.charAt(1) - ARG_NUM_LIMIT;
if (result != null) {
result.insert(startIndex, compiledPattern, 2, 2 + prefixLength, field);
}
length += prefixLength;
offset = 3 + prefixLength;
if (prefixLength > 0) {
result.insert(startIndex, compiledPattern, 2, 2 + prefixLength, field);
}
if (offset < compiledPattern.length()) {
int suffixLength = compiledPattern.charAt(offset) - ARG_NUM_LIMIT;
if (result != null) {
result.insert(
endIndex + length, compiledPattern, offset + 1, offset + suffixLength + 1, field);
}
length += suffixLength;
if (suffixLength > 0) {
result.insert(
endIndex + prefixLength,
compiledPattern,
1 + suffixOffset,
1 + suffixOffset + suffixLength,
field);
}
return length;
return prefixLength + suffixLength;
}
/** TODO: Move this to a test file somewhere, once we figure out what to do with the method. */
@ -108,8 +120,8 @@ public class SimpleModifier extends Modifier.BaseModifier {
SimpleFormatterImpl.compileToStringMinMaxArguments(pattern, new StringBuilder(), 1, 1);
NumberStringBuilder output = new NumberStringBuilder();
output.append((String) outputs[j][0], null);
formatAsPrefixSuffix(
compiledPattern, output, (Integer) outputs[j][1], (Integer) outputs[j][2], null);
new SimpleModifier(compiledPattern, null, false)
.apply(output, (Integer) outputs[j][1], (Integer) outputs[j][2]);
String expected = expecteds[j][i];
String actual = output.toString();
assert expected.equals(actual);

View File

@ -7,7 +7,6 @@ import java.math.RoundingMode;
import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.impl.number.Rounder;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
public class SignificantDigitsRounder extends Rounder {
@ -65,28 +64,13 @@ public class SignificantDigitsRounder extends Rounder {
* @return The property bag, for chaining.
*/
public IProperties setMaximumSignificantDigits(int maximumSignificantDigits);
static SignificantDigitsMode DEFAULT_SIGNIFICANT_DIGITS_MODE = null;
/** @see #setSignificantDigitsMode */
public SignificantDigitsMode getSignificantDigitsMode();
/**
* Sets the strategy used when reconciling significant digits versus integer and fraction
* lengths.
*
* @param significantDigitsMode One of the options from {@link SignificantDigitsMode}.
* @return The property bag, for chaining.
*/
public IProperties setSignificantDigitsMode(SignificantDigitsMode significantDigitsMode);
}
public static boolean useSignificantDigits(IProperties properties) {
return properties.getMinimumSignificantDigits()
!= IProperties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS
|| properties.getMaximumSignificantDigits()
!= IProperties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS
|| properties.getSignificantDigitsMode() != IProperties.DEFAULT_SIGNIFICANT_DIGITS_MODE;
!= IProperties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS;
}
public static SignificantDigitsRounder getInstance(IProperties properties) {
@ -95,7 +79,6 @@ public class SignificantDigitsRounder extends Rounder {
private final int minSig;
private final int maxSig;
private final SignificantDigitsMode mode;
private SignificantDigitsRounder(IProperties properties) {
super(properties);
@ -103,8 +86,6 @@ public class SignificantDigitsRounder extends Rounder {
int _maxSig = properties.getMaximumSignificantDigits();
minSig = _minSig < 1 ? 1 : _minSig > 1000 ? 1000 : _minSig;
maxSig = _maxSig < 0 ? 1000 : _maxSig < minSig ? minSig : _maxSig > 1000 ? 1000 : _maxSig;
SignificantDigitsMode _mode = properties.getSignificantDigitsMode();
mode = _mode == null ? SignificantDigitsMode.OVERRIDE_MAXIMUM_FRACTION : _mode;
}
@Override
@ -123,47 +104,7 @@ public class SignificantDigitsRounder extends Rounder {
magMaxSig = effectiveMag - maxSig;
// Step 1: pick the rounding magnitude and apply.
int roundingMagnitude;
switch (mode) {
case OVERRIDE_MAXIMUM_FRACTION:
// Always round to maxSig.
// Of the six possible orders:
// Case 1: minSig, maxSig, minFrac, maxFrac -- maxSig wins
// Case 2: minSig, minFrac, maxSig, maxFrac -- maxSig wins
// Case 3: minSig, minFrac, maxFrac, maxSig -- maxSig wins
// Case 4: minFrac, minSig, maxSig, maxFrac -- maxSig wins
// Case 5: minFrac, minSig, maxFrac, maxSig -- maxSig wins
// Case 6: minFrac, maxFrac, minSig, maxSig -- maxSig wins
roundingMagnitude = magMaxSig;
break;
case RESPECT_MAXIMUM_FRACTION:
// Round to the strongest of maxFrac, maxInt, and maxSig.
// Of the six possible orders:
// Case 1: minSig, maxSig, minFrac, maxFrac -- maxSig wins
// Case 2: minSig, minFrac, maxSig, maxFrac -- maxSig wins
// Case 3: minSig, minFrac, maxFrac, maxSig -- maxFrac wins --> differs from default
// Case 4: minFrac, minSig, maxSig, maxFrac -- maxSig wins
// Case 5: minFrac, minSig, maxFrac, maxSig -- maxFrac wins --> differs from default
// Case 6: minFrac, maxFrac, minSig, maxSig -- maxFrac wins --> differs from default
//
// Math.max() picks the rounding magnitude farthest to the left (most significant).
// Math.min() picks the rounding magnitude farthest to the right (least significant).
roundingMagnitude = Math.max(-maxFrac, magMaxSig);
break;
case ENSURE_MINIMUM_SIGNIFICANT:
// Round to the strongest of maxFrac and maxSig, and always ensure minSig.
// Of the six possible orders:
// Case 1: minSig, maxSig, minFrac, maxFrac -- maxSig wins
// Case 2: minSig, minFrac, maxSig, maxFrac -- maxSig wins
// Case 3: minSig, minFrac, maxFrac, maxSig -- maxFrac wins --> differs from default
// Case 4: minFrac, minSig, maxSig, maxFrac -- maxSig wins
// Case 5: minFrac, minSig, maxFrac, maxSig -- maxFrac wins --> differs from default
// Case 6: minFrac, maxFrac, minSig, maxSig -- minSig wins --> differs from default
roundingMagnitude = Math.min(magMinSig, Math.max(-maxFrac, magMaxSig));
break;
default:
throw new AssertionError();
}
int roundingMagnitude = magMaxSig;
input.roundToMagnitude(roundingMagnitude, mathContext);
// In case magnitude changed:
@ -177,23 +118,8 @@ public class SignificantDigitsRounder extends Rounder {
magMaxSig = effectiveMag - maxSig;
// Step 2: pick the number of visible digits.
switch (mode) {
case OVERRIDE_MAXIMUM_FRACTION:
// Ensure minSig is always displayed.
input.setIntegerLength(minInt, maxInt);
input.setFractionLength(Math.max(minFrac, -magMinSig), Integer.MAX_VALUE);
break;
case RESPECT_MAXIMUM_FRACTION:
// Ensure minSig is displayed, unless doing so is in violation of maxFrac.
input.setIntegerLength(minInt, maxInt);
input.setFractionLength(Math.min(maxFrac, Math.max(minFrac, -magMinSig)), maxFrac);
break;
case ENSURE_MINIMUM_SIGNIFICANT:
// Follow minInt/minFrac, but ensure all digits are allowed to be visible.
input.setIntegerLength(minInt, maxInt);
input.setFractionLength(minFrac, Integer.MAX_VALUE);
break;
}
input.setIntegerLength(minInt, maxInt);
input.setFractionLength(Math.max(minFrac, -magMinSig), Integer.MAX_VALUE);
}
@Override
@ -201,6 +127,5 @@ public class SignificantDigitsRounder extends Rounder {
super.export(properties);
properties.setMinimumSignificantDigits(minSig);
properties.setMaximumSignificantDigits(maxSig);
properties.setSignificantDigitsMode(mode);
}
}

View File

@ -12,7 +12,6 @@ package com.ibm.icu.text;
import java.text.ParsePosition;
import java.util.Locale;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
@ -121,17 +120,13 @@ public class CompactDecimalFormat extends DecimalFormat {
* @param style the compact style
*/
CompactDecimalFormat(ULocale locale, CompactStyle style) {
// Use the locale's default pattern
String pattern = getPattern(locale, 0);
// Minimal properties: let the non-shim code path do most of the logic for us.
symbols = DecimalFormatSymbols.getInstance(locale);
properties = new Properties();
properties.setCompactStyle(style);
properties.setGroupingSize(-2); // do not forward grouping information
properties.setMinimumGroupingDigits(2);
exportedProperties = new Properties();
setPropertiesFromPattern(pattern, PatternString.IGNORE_ROUNDING_ALWAYS);
if (style == CompactStyle.SHORT) {
// TODO: This was setGroupingUsed(false) in ICU 58. Is it okay that I changed it for ICU 59?
properties.setMinimumGroupingDigits(2);
}
refreshFormatter();
}

View File

@ -13,9 +13,6 @@ import java.text.FieldPosition;
import java.text.ParseException;
import java.text.ParsePosition;
import com.ibm.icu.impl.number.Endpoint;
import com.ibm.icu.impl.number.Format.SingularFormat;
import com.ibm.icu.impl.number.FormatQuantity4;
import com.ibm.icu.impl.number.Parse;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
@ -33,6 +30,12 @@ import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.ULocale.Category;
import newapi.NumberFormatter.LocalizedNumberFormatter;
import newapi.NumberFormatter.NumberFormatterResult;
import newapi.impl.MacroProps;
import newapi.impl.NumberFormatterImpl;
import newapi.impl.NumberPropertyMapper;
/**
* {@icuenhanced java.text.DecimalFormat}.{@icu _usage_} <code>DecimalFormat</code> is the primary
* concrete subclass of {@link NumberFormat}. It has a variety of features designed to make it
@ -107,9 +110,8 @@ import com.ibm.icu.util.ULocale.Category;
* digits are shown. This is most common in scientific notation.
* </ol>
*
* <p>It is possible to specify both a magnitude and a number of significant digits. If used
* together, the <em>significant digits mode</em> determines how conflicts between fraction digits
* and signiciant digits are resolved. For more information, see {@link #setSignificantDigitsMode}.
* <p>It is not possible to specify more than one rounding strategy. For example, setting a rounding
* increment in conjunction with significant digits results in undefined behavior.
*
* <p>It is also possible to specify the <em>rounding mode</em> to use. The default rounding mode is
* "half even", which rounds numbers to their closest increment, with ties broken in favor of
@ -265,7 +267,7 @@ public class DecimalFormat extends NumberFormat {
* #format} method uses the formatter directly without needing to synchronize. Volatile because
* threads may read and write at the same time.
*/
transient volatile SingularFormat formatter;
transient volatile LocalizedNumberFormatter formatter;
/**
* The effective properties as exported from the formatter object. Volatile because threads may
@ -683,9 +685,9 @@ public class DecimalFormat extends NumberFormat {
*/
@Override
public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
FormatQuantity4 fq = new FormatQuantity4(number);
formatter.format(fq, result, fieldPosition);
fq.populateUFieldPosition(fieldPosition);
NumberFormatterResult output = formatter.format(number);
output.populateFieldPosition(fieldPosition, result.length());
output.appendTo(result);
return result;
}
@ -696,9 +698,9 @@ public class DecimalFormat extends NumberFormat {
*/
@Override
public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
FormatQuantity4 fq = new FormatQuantity4(number);
formatter.format(fq, result, fieldPosition);
fq.populateUFieldPosition(fieldPosition);
NumberFormatterResult output = formatter.format(number);
output.populateFieldPosition(fieldPosition, result.length());
output.appendTo(result);
return result;
}
@ -709,9 +711,9 @@ public class DecimalFormat extends NumberFormat {
*/
@Override
public StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition) {
FormatQuantity4 fq = new FormatQuantity4(number);
formatter.format(fq, result, fieldPosition);
fq.populateUFieldPosition(fieldPosition);
NumberFormatterResult output = formatter.format(number);
output.populateFieldPosition(fieldPosition, result.length());
output.appendTo(result);
return result;
}
@ -723,9 +725,9 @@ public class DecimalFormat extends NumberFormat {
@Override
public StringBuffer format(
java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
FormatQuantity4 fq = new FormatQuantity4(number);
formatter.format(fq, result, fieldPosition);
fq.populateUFieldPosition(fieldPosition);
NumberFormatterResult output = formatter.format(number);
output.populateFieldPosition(fieldPosition, result.length());
output.appendTo(result);
return result;
}
@ -736,9 +738,9 @@ public class DecimalFormat extends NumberFormat {
*/
@Override
public StringBuffer format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
FormatQuantity4 fq = new FormatQuantity4(number.toBigDecimal());
formatter.format(fq, result, fieldPosition);
fq.populateUFieldPosition(fieldPosition);
NumberFormatterResult output = formatter.format(number);
output.populateFieldPosition(fieldPosition, result.length());
output.appendTo(result);
return result;
}
@ -751,9 +753,8 @@ public class DecimalFormat extends NumberFormat {
public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
if (!(obj instanceof Number)) throw new IllegalArgumentException();
Number number = (Number) obj;
FormatQuantity4 fq = new FormatQuantity4(number);
AttributedCharacterIterator result = formatter.formatToCharacterIterator(fq);
return result;
NumberFormatterResult output = formatter.format(number);
return output.toAttributedCharacterIterator();
}
/**
@ -763,27 +764,9 @@ public class DecimalFormat extends NumberFormat {
*/
@Override
public StringBuffer format(CurrencyAmount currAmt, StringBuffer toAppendTo, FieldPosition pos) {
// TODO: This is ugly (although not as ugly as it was in ICU 58).
// Currency should be a free parameter, not in property bag. Fix in ICU 60.
Properties cprops = threadLocalProperties.get();
SingularFormat fmt = null;
synchronized (this) {
// Use the pre-compiled formatter if possible. Otherwise, copy the properties
// and build our own formatter.
// TODO: Consider using a static format path here.
if (currAmt.getCurrency().equals(properties.getCurrency())) {
fmt = formatter;
} else {
cprops.copyFrom(properties);
}
}
if (fmt == null) {
cprops.setCurrency(currAmt.getCurrency());
fmt = Endpoint.fromBTA(cprops, symbols);
}
FormatQuantity4 fq = new FormatQuantity4(currAmt.getNumber());
fmt.format(fq, toAppendTo, pos);
fq.populateUFieldPosition(pos);
NumberFormatterResult output = formatter.format(currAmt);
output.populateFieldPosition(pos, toAppendTo.length());
output.appendTo(toAppendTo);
return toAppendTo;
}
@ -815,8 +798,11 @@ public class DecimalFormat extends NumberFormat {
@Override
public CurrencyAmount parseCurrency(CharSequence text, ParsePosition parsePosition) {
try {
// TODO(sffc): Make this thread-safe
CurrencyAmount result = Parse.parseCurrency(text, parsePosition, properties, symbols);
Properties pprops = threadLocalProperties.get();
synchronized (this) {
pprops.copyFrom(properties);
}
CurrencyAmount result = Parse.parseCurrency(text, parsePosition, pprops, symbols);
if (result == null) return null;
Number number = result.getNumber();
// Backwards compatibility: return com.ibm.icu.math.BigDecimal
@ -872,8 +858,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized String getPositivePrefix() {
String result = exportedProperties.getPositivePrefix();
return (result == null) ? "" : result;
return formatter.format(1).getPrefix();
}
/**
@ -910,8 +895,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized String getNegativePrefix() {
String result = exportedProperties.getNegativePrefix();
return (result == null) ? "" : result;
return formatter.format(-1).getPrefix();
}
/**
@ -948,8 +932,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized String getPositiveSuffix() {
String result = exportedProperties.getPositiveSuffix();
return (result == null) ? "" : result;
return formatter.format(1).getSuffix();
}
/**
@ -986,8 +969,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized String getNegativeSuffix() {
String result = exportedProperties.getNegativeSuffix();
return (result == null) ? "" : result;
return formatter.format(-1).getSuffix();
}
/**
@ -1516,7 +1498,6 @@ public class DecimalFormat extends NumberFormat {
} else {
properties.setMinimumSignificantDigits(Properties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS);
properties.setMaximumSignificantDigits(Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS);
properties.setSignificantDigitsMode(null);
}
refreshFormatter();
}
@ -1545,7 +1526,6 @@ public class DecimalFormat extends NumberFormat {
* and then you set maxInt=3, then minInt will be changed to 3.
*
* @param value The minimum number of significant digits to display.
* @see #setSignificantDigitsMode
* @category Rounding
* @stable ICU 3.0
*/
@ -1588,7 +1568,6 @@ public class DecimalFormat extends NumberFormat {
* @see #setRoundingMode
* @see #setRoundingIncrement
* @see #setMaximumFractionDigits
* @see #setSignificantDigitsMode
* @category Rounding
* @stable ICU 3.0
*/
@ -1601,60 +1580,6 @@ public class DecimalFormat extends NumberFormat {
refreshFormatter();
}
/**
* {@icu} Returns the current significant digits mode.
*
* @see #setSignificantDigitsMode
* @category Rounding
* @internal
* @deprecated ICU 59: This API is a technical preview. It may change in an upcoming release.
*/
@Deprecated
public synchronized SignificantDigitsMode getSignificantDigitsMode() {
return exportedProperties.getSignificantDigitsMode();
}
/**
* {@icu} <strong>Rounding and Digit Limits:</strong> Sets the strategy used for resolving
* minimum/maximum significant digits when minimum/maximum integer and/or fraction digits are
* specified. There are three modes:
*
* <ul>
* <li>Mode A: OVERRIDE_MAXIMUM_FRACTION. This is the default. Settings in maximum fraction are
* ignored.
* <li>Mode B: RESPECT_MAXIMUM_FRACTION. Round to maximum fraction even if doing so will prevent
* minimum significant from being respected.
* <li>Mode C: ENSURE_MINIMUM_SIGNIFICANT. Respect maximum fraction, but always ensure that
* minimum significant digits are shown.
* </ul>
*
* <p>The following table illustrates the difference. Below, minFrac=1, maxFrac=2, minSig=3, and
* maxSig=4:
*
* <pre>
* Mode A | Mode B | Mode C
* ---------+----------+----------
* 12340.0 | 12340.0 | 12340.0
* 1234.0 | 1234.0 | 1234.0
* 123.4 | 123.4 | 123.4
* 12.34 | 12.34 | 12.34
* 1.234 | 1.23 | 1.23
* 0.1234 | 0.12 | 0.123
* 0.01234 | 0.01 | 0.0123
* 0.001234 | 0.00 | 0.00123
* </pre>
*
* @param mode The significant digits mode to use.
* @category Rounding
* @internal
* @deprecated ICU 59: This API is a technical preview. It may change in an upcoming release.
*/
@Deprecated
public synchronized void setSignificantDigitsMode(SignificantDigitsMode mode) {
properties.setSignificantDigitsMode(mode);
refreshFormatter();
}
/**
* Returns the minimum number of characters in formatted output.
*
@ -1663,7 +1588,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized int getFormatWidth() {
return exportedProperties.getFormatWidth();
return properties.getFormatWidth();
}
/**
@ -1699,7 +1624,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized char getPadCharacter() {
CharSequence paddingString = exportedProperties.getPadString();
CharSequence paddingString = properties.getPadString();
if (paddingString == null) {
return '.'; // TODO: Is this the correct behavior?
} else {
@ -1732,7 +1657,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized int getPadPosition() {
PadPosition loc = exportedProperties.getPadPosition();
PadPosition loc = properties.getPadPosition();
return (loc == null) ? PAD_BEFORE_PREFIX : loc.toOld();
}
@ -1800,7 +1725,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized byte getMinimumExponentDigits() {
return (byte) exportedProperties.getMinimumExponentDigits();
return (byte) properties.getMinimumExponentDigits();
}
/**
@ -1828,7 +1753,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized boolean isExponentSignAlwaysShown() {
return exportedProperties.getExponentSignAlwaysShown();
return properties.getExponentSignAlwaysShown();
}
/**
@ -1898,7 +1823,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized int getGroupingSize() {
return exportedProperties.getGroupingSize();
return properties.getGroupingSize();
}
/**
@ -1930,7 +1855,12 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized int getSecondaryGroupingSize() {
return exportedProperties.getSecondaryGroupingSize();
int grouping1 = properties.getGroupingSize();
int grouping2 = properties.getSecondaryGroupingSize();
if (grouping1 == grouping2 || grouping2 < 0) {
return 0;
}
return properties.getSecondaryGroupingSize();
}
/**
@ -1991,7 +1921,7 @@ public class DecimalFormat extends NumberFormat {
* @stable ICU 2.0
*/
public synchronized boolean isDecimalSeparatorAlwaysShown() {
return exportedProperties.getDecimalSeparatorAlwaysShown();
return properties.getDecimalSeparatorAlwaysShown();
}
/**
@ -2471,9 +2401,7 @@ public class DecimalFormat extends NumberFormat {
*/
@Deprecated
public IFixedDecimal getFixedDecimal(double number) {
FormatQuantity4 fq = new FormatQuantity4(number);
formatter.format(fq);
return fq;
return formatter.format(number).getFixedDecimal();
}
private static final ThreadLocal<Properties> threadLocalProperties =
@ -2491,9 +2419,18 @@ public class DecimalFormat extends NumberFormat {
// The only time when this happens is during legacy deserialization.
return;
}
formatter = Endpoint.fromBTA(properties, symbols);
exportedProperties.clear();
formatter.export(exportedProperties);
MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
ULocale locale = this.getLocale(ULocale.ACTUAL_LOCALE);
if (locale == null) {
// Constructor
locale = symbols.getLocale(ULocale.ACTUAL_LOCALE);
}
if (locale == null) {
// Deserialization
locale = symbols.getULocale();
}
assert locale != null;
formatter = NumberFormatterImpl.fromMacros(macros).locale(locale);
}
/**
@ -2561,46 +2498,6 @@ public class DecimalFormat extends NumberFormat {
public void set(Properties props);
}
/**
* An enum containing the choices for significant digits modes.
*
* @see #setSignificantDigitsMode
* @internal
* @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
*/
@Deprecated
public static enum SignificantDigitsMode {
/**
* Respect significant digits counts, ignoring the fraction length.
*
* @see DecimalFormat#setSignificantDigitsMode
* @internal
* @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
*/
@Deprecated
OVERRIDE_MAXIMUM_FRACTION,
/**
* Respect the fraction length, overriding significant digits counts if necessary.
*
* @see DecimalFormat#setSignificantDigitsMode
* @internal
* @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
*/
@Deprecated
RESPECT_MAXIMUM_FRACTION,
/**
* Respect minimum significant digits, overriding fraction length if necessary.
*
* @see DecimalFormat#setSignificantDigitsMode
* @internal
* @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
*/
@Deprecated
ENSURE_MINIMUM_SIGNIFICANT
}
/**
* {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
* characters inserted before the prefix.

View File

@ -259,8 +259,8 @@ $**####,##0 1234 $***1\u00a0234 K
// In J ICU adds padding as if 'EUR' is only 2 chars (2 * 0xa4)
\u00a4\u00a4 **####0.00 433.0 EUR *433,00 JK
// In J ICU adds padding as if 'EUR' is only 2 chars (2 * 0xa4)
// S fails this one because the test code bypasses CurrencyUsage
\u00a4\u00a4 **#######0 433.0 EUR *433,00 JKS
// S and Q fail this one because the test code bypasses CurrencyUsage
\u00a4\u00a4 **#######0 433.0 EUR *433,00 JKSQ
test padding and currencies
begin
@ -338,8 +338,8 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
// JDK gives E0 instead of allowing for unlimited precision
// S obeys the maximum integer digits and returns .299792458E9
0 0 0 0 2.99792458E8 KS
// JDK and S give .299792E9
0 1 0 5 2.9979E8 KS
// JDK and S give .299792E9; Q gives 2.99792E8
0 1 0 5 2.9979E8 KSQ
// JDK gives 300E6
0 3 0 0 299.792458E6 K
// JDK gives 299.8E6 (maybe maxInt + maxFrac instead of minInt + maxFrac)?
@ -356,12 +356,13 @@ minIntegerDigits maxIntegerDigits minFractionDigits maxFractionDigits output bre
// JDK gives E0
// S obeys the maximum integer digits
0 0 1 0 2.99792458E8 KS
// JDK gives .2998E9
0 0 0 4 2.998E8 KS
// JDK and S give .2998E9
0 0 0 4 2.998E8 KSQ
// S correctly formats this as 29.979246E7.
// JDK uses 8 + 6 for significant digits instead of 2 + 6
// J and C return 2.9979246E8.
2 8 1 6 29.979246E7 CJK
// TODO: Merge trunk
2 8 1 6 29.979246E7 CJKQ
// Treat max int digits > 8 as being the same as min int digits.
// This behavior is not spelled out in the specification.
// JDK fails here because it tries to use 9 + 6 = 15 sig digits.
@ -405,12 +406,12 @@ begin
format maxIntegerDigits output breaks
123 1 3
0 0 0
// S ignores max integer if it is less than zero and prints "123"
123 -2147483648 0 S
// S and Q ignore max integer if it is less than zero and prints "123"
123 -2147483648 0 SQ
12345 1 5
12345 -2147483648 0 S
12345 -2147483648 0 SQ
5.3 1 5.3
5.3 -2147483648 .3 S
5.3 -2147483648 .3 SQ
test patterns with zero
set locale en
@ -489,8 +490,9 @@ output grouping breaks grouping2 minGroupingDigits
1,2345,6789 4
1,23,45,6789 4 K 2
1,23,45,6789 4 K 2 2
// Q only supports minGrouping<=2
123,456789 6 6 3
123456789 6 JK 6 4
123456789 6 JKQ 6 4
test multiplier setters
set locale en_US
@ -498,8 +500,10 @@ begin
format multiplier output breaks
23 -12 -276
23 -1 -23
// ICU4J and JDK throw exception on zero multiplier. ICU4C does not.
23 0 23 JKS
// ICU4J and JDK throw exception on zero multiplier.
// ICU4C and S print 23.
// Q multiplies by zero and prints 0.
23 0 0 CJKS
23 1 23
23 12 276
-23 12 -276
@ -513,8 +517,9 @@ begin
format output breaks
-0.35 -0.25 K
0.35 0.25 K
0.39 0.5 K
0.62 0.5 K
// Q doesn't support mixing minFrac with roundingIncrement (prints 0.50).
0.39 0.5 KQ
0.62 0.5 KQ
0.63 0.75 K
test padding setters
@ -539,20 +544,19 @@ output breaks useScientific
test rounding mode setters
set locale en_US
set pattern 0.#
set roundingIncrement 0.5
set pattern 0.5
begin
format roundingMode output breaks
1.24 halfUp 1 K
1.24 halfUp 1.0 K
1.25 halfUp 1.5 K
1.25 halfDown 1 K
1.25 halfDown 1.0 K
1.26 halfDown 1.5 K
1.25 halfEven 1 K
1.25 halfEven 1.0 K
-1.01 up -1.5 K
-1.49 down -1 K
-1.49 down -1.0 K
1.01 up 1.5 K
1.49 down 1 K
-1.01 ceiling -1
1.49 down 1.0 K
-1.01 ceiling -1.0
-1.49 floor -1.5
test currency usage setters
@ -584,7 +588,7 @@ set locale en
set currency USD
begin
pattern format output breaks
# 123 123 S
# 123 123 SQ
// Currency rounding should always override the pattern.
// K prints the currency in ISO format for some reason.
\u00a4# 123 $123.00 K
@ -659,7 +663,8 @@ begin
format output breaks
Inf [\u221e]
-Inf (\u221e) K
NaN NaN K
// Q prints the affixes
NaN NaN KQ
test nan and infinity with multiplication
set locale en
@ -680,10 +685,11 @@ Inf beforePrefix $$$\u221e$ K
Inf afterPrefix $$$ \u221e$ K
Inf beforeSuffix $$$\u221e $ K
Inf afterSuffix $$$\u221e$ K
NaN beforePrefix NaN K
NaN afterPrefix NaN K
NaN beforeSuffix NaN K
NaN afterSuffix NaN K
// Q gets $$$NaN$
NaN beforePrefix NaN KQ
NaN afterPrefix NaN KQ
NaN beforeSuffix NaN KQ
NaN afterSuffix NaN KQ
test apply formerly localized patterns
begin
@ -1540,8 +1546,9 @@ set maxSigDigits 2
begin
format output breaks
// C and J get "1"
// Q gets "1.0"
// K gets "1.1" (??)
0.975 0.98 CJK
0.975 0.98 CJKQ
test lenient parse currency match
// This test is for #13112

View File

@ -102,7 +102,7 @@ public class CompactDecimalFormatTest extends TestFmwk {
{1234567890123f, "1,2 билиона"},
{12345678901234f, "12 билиона"},
{123456789012345f, "120 билиона"},
{1234567890123456f, "1.200 билиона"},
{1234567890123456f, "1200 билиона"},
};
Object[][] SerbianTestDataLongNegative = {
@ -125,7 +125,7 @@ public class CompactDecimalFormatTest extends TestFmwk {
{-1234567890123f, "-1,2 билиона"},
{-12345678901234f, "-12 билиона"},
{-123456789012345f, "-120 билиона"},
{-1234567890123456f, "-1.200 билиона"},
{-1234567890123456f, "-1200 билиона"},
};
Object[][] JapaneseTestData = {
@ -363,10 +363,10 @@ public class CompactDecimalFormatTest extends TestFmwk {
// and rounded to the unit for compact formats with three or more zeros.
CompactDecimalFormat cdf =
CompactDecimalFormat.getInstance(ULocale.ENGLISH, CompactStyle.SHORT);
assertEquals("Default significant digits", "120K", cdf.format(123456));
assertEquals("Default significant digits", "123K", cdf.format(123456));
assertEquals("Default significant digits", "12K", cdf.format(12345));
assertEquals("Default significant digits", "1.2K", cdf.format(1234));
assertEquals("Default significant digits", "120", cdf.format(123));
assertEquals("Default significant digits", "123", cdf.format(123));
}
@Test
@ -636,8 +636,9 @@ public class CompactDecimalFormatTest extends TestFmwk {
public void TestDigitDisplay() {
CompactDecimalFormat cdf = CompactDecimalFormat.getInstance(ULocale.US, CompactStyle.SHORT);
cdf.setMinimumSignificantDigits(2);
cdf.setMaximumSignificantDigits(3);
String actual = cdf.format(70123.45678);
assertEquals("Should not display any extra fraction digits", "70K", actual);
assertEquals("Should not display any extra fraction digits", "70.1K", actual);
}
@Test
@ -667,7 +668,7 @@ public class CompactDecimalFormatTest extends TestFmwk {
props.setCompactCustomData(customData);
}
});
assertEquals("Below custom range", "120", cdf.format(123));
assertEquals("Below custom range", "123", cdf.format(123));
assertEquals("Plural form one", "1 qwerty", cdf.format(1000));
assertEquals("Plural form other", "1.2 dvorak", cdf.format(1234));
assertEquals("Above custom range", "12 dvorak", cdf.format(12345));

View File

@ -59,8 +59,7 @@ public class IntlTestDecimalFormatAPI extends com.ibm.icu.dev.test.TestFmwk
String pat = ",##0.0000";
DecimalFormat dec = new DecimalFormat(pat);
dec.setRoundingMode(BigDecimal.ROUND_HALF_UP);
double roundinginc = 0.0001;
dec.setRoundingIncrement(roundinginc);
dec.setRoundingIncrement(new java.math.BigDecimal("0.0001"));
String str = dec.format(number);
if (!str.equals(expected)) {
errln("Fail: " + number + " x \"" + pat + "\" = \"" +

View File

@ -278,7 +278,7 @@ public class IntlTestDecimalFormatAPIC extends com.ibm.icu.dev.test.TestFmwk {
}
//for +2.55 with RoundingIncrement=1.0
pat.setRoundingIncrement(1.0);
pat.setRoundingIncrement(java.math.BigDecimal.ONE);
resultStr = pat.format(Roundingnumber);
message = "round(" + Roundingnumber
+ "," + mode + ",FALSE) with RoundingIncrement=1.0==>";

View File

@ -124,7 +124,7 @@ public class IntlTestDecimalFormatSymbolsC extends com.ibm.icu.dev.test.TestFmwk
sym.setPercent('P');
verify(34.5, "00 %", sym, "3450 P");
sym.setCurrencySymbol("D");
verify(34.5, "\u00a4##.##", sym, "D34.50");
verify(34.5, "\u00a4##.##", sym, "D 34.50");
sym.setGroupingSeparator('|');
verify(3456.5, "0,000.##", sym, "3|456S5");
}

View File

@ -1660,9 +1660,9 @@ public class MeasureUnitTest extends TestFmwk {
assertEquals("Wide currency", "1.00 US dollars", mf.format(USD_1));
assertEquals("Wide currency", "2.00 US dollars", mf.format(USD_2));
mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT);
assertEquals("short currency", "-USD1.00", mf.format(USD_NEG_1));
assertEquals("short currency", "USD1.00", mf.format(USD_1));
assertEquals("short currency", "USD2.00", mf.format(USD_2));
assertEquals("short currency", "-USD 1.00", mf.format(USD_NEG_1));
assertEquals("short currency", "USD 1.00", mf.format(USD_1));
assertEquals("short currency", "USD 2.00", mf.format(USD_2));
mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NARROW);
assertEquals("narrow currency", "-$1.00", mf.format(USD_NEG_1));
assertEquals("narrow currency", "$1.00", mf.format(USD_1));
@ -1673,13 +1673,13 @@ public class MeasureUnitTest extends TestFmwk {
assertEquals("numeric currency", "$2.00", mf.format(USD_2));
mf = MeasureFormat.getInstance(ULocale.JAPAN, FormatWidth.WIDE);
assertEquals("Wide currency", "-1.00\u7C73\u30C9\u30EB", mf.format(USD_NEG_1));
assertEquals("Wide currency", "1.00\u7C73\u30C9\u30EB", mf.format(USD_1));
assertEquals("Wide currency", "2.00\u7C73\u30C9\u30EB", mf.format(USD_2));
assertEquals("Wide currency", "-1.00 \u7C73\u30C9\u30EB", mf.format(USD_NEG_1));
assertEquals("Wide currency", "1.00 \u7C73\u30C9\u30EB", mf.format(USD_1));
assertEquals("Wide currency", "2.00 \u7C73\u30C9\u30EB", mf.format(USD_2));
Measure CAD_1 = new Measure(1.0, Currency.getInstance("CAD"));
mf = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
assertEquals("short currency", "CAD1.00", mf.format(CAD_1));
assertEquals("short currency", "CAD 1.00", mf.format(CAD_1));
}
@Test
@ -1997,7 +1997,10 @@ public class MeasureUnitTest extends TestFmwk {
}
}
for (String type : MeasureUnit.getAvailableTypes()) {
if (type.equals("currency") || type.equals("compound") || type.equals("coordinate")) {
if (type.equals("currency")
|| type.equals("compound")
|| type.equals("coordinate")
|| type.equals("dimensionless")) {
continue;
}
for (MeasureUnit unit : MeasureUnit.getAvailable(type)) {

View File

@ -7,6 +7,7 @@ import java.math.RoundingMode;
import java.text.ParseException;
import java.text.ParsePosition;
import org.junit.Ignore;
import org.junit.Test;
import com.ibm.icu.dev.test.TestUtil;
@ -29,6 +30,11 @@ import com.ibm.icu.text.DecimalFormat_ICU58;
import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
import newapi.NumberFormatter.LocalizedNumberFormatter;
import newapi.impl.MacroProps;
import newapi.impl.NumberFormatterImpl;
import newapi.impl.NumberPropertyMapper;
public class NumberFormatDataDrivenTest {
private static ULocale EN = new ULocale("en");
@ -431,7 +437,7 @@ public class NumberFormatDataDrivenTest {
}
};
private DataDrivenNumberFormatTestUtility.CodeUnderTest Shane =
private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU59 =
new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
@Override
@ -667,117 +673,154 @@ public class NumberFormatDataDrivenTest {
public String select(DataDrivenNumberFormatTestData tuple) {
return null;
}
};
private void propertiesFromTuple(
DataDrivenNumberFormatTestData tuple, Properties properties) {
if (tuple.minIntegerDigits != null) {
properties.setMinimumIntegerDigits(tuple.minIntegerDigits);
}
if (tuple.maxIntegerDigits != null) {
properties.setMaximumIntegerDigits(tuple.maxIntegerDigits);
}
if (tuple.minFractionDigits != null) {
properties.setMinimumFractionDigits(tuple.minFractionDigits);
}
if (tuple.maxFractionDigits != null) {
properties.setMaximumFractionDigits(tuple.maxFractionDigits);
}
if (tuple.currency != null) {
properties.setCurrency(tuple.currency);
}
if (tuple.minGroupingDigits != null) {
properties.setMinimumGroupingDigits(tuple.minGroupingDigits);
}
if (tuple.useSigDigits != null) {
// TODO
}
if (tuple.minSigDigits != null) {
properties.setMinimumSignificantDigits(tuple.minSigDigits);
}
if (tuple.maxSigDigits != null) {
properties.setMaximumSignificantDigits(tuple.maxSigDigits);
}
if (tuple.useGrouping != null && tuple.useGrouping == 0) {
properties.setGroupingSize(-1);
properties.setSecondaryGroupingSize(-1);
}
if (tuple.multiplier != null) {
properties.setMultiplier(new BigDecimal(tuple.multiplier));
}
if (tuple.roundingIncrement != null) {
properties.setRoundingIncrement(new BigDecimal(tuple.roundingIncrement.toString()));
}
if (tuple.formatWidth != null) {
properties.setFormatWidth(tuple.formatWidth);
}
if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
properties.setPadString(tuple.padCharacter.toString());
}
if (tuple.useScientific != null) {
properties.setMinimumExponentDigits(
tuple.useScientific != 0 ? 1 : Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS);
}
if (tuple.grouping != null) {
properties.setGroupingSize(tuple.grouping);
}
if (tuple.grouping2 != null) {
properties.setSecondaryGroupingSize(tuple.grouping2);
}
if (tuple.roundingMode != null) {
properties.setRoundingMode(RoundingMode.valueOf(tuple.roundingMode));
}
if (tuple.currencyUsage != null) {
properties.setCurrencyUsage(tuple.currencyUsage);
}
if (tuple.minimumExponentDigits != null) {
properties.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue());
}
if (tuple.exponentSignAlwaysShown != null) {
properties.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0);
}
if (tuple.decimalSeparatorAlwaysShown != null) {
properties.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0);
}
if (tuple.padPosition != null) {
properties.setPadPosition(PadPosition.fromOld(tuple.padPosition));
}
if (tuple.positivePrefix != null) {
properties.setPositivePrefix(tuple.positivePrefix);
}
if (tuple.positiveSuffix != null) {
properties.setPositiveSuffix(tuple.positiveSuffix);
}
if (tuple.negativePrefix != null) {
properties.setNegativePrefix(tuple.negativePrefix);
}
if (tuple.negativeSuffix != null) {
properties.setNegativeSuffix(tuple.negativeSuffix);
}
if (tuple.localizedPattern != null) {
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(tuple.locale);
String converted =
PatternString.convertLocalized(tuple.localizedPattern, symbols, false);
PatternString.parseToExistingProperties(converted, properties);
}
if (tuple.lenient != null) {
properties.setParseMode(tuple.lenient == 0 ? ParseMode.STRICT : ParseMode.LENIENT);
}
if (tuple.parseIntegerOnly != null) {
properties.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
}
if (tuple.parseCaseSensitive != null) {
properties.setParseCaseSensitive(tuple.parseCaseSensitive != 0);
}
if (tuple.decimalPatternMatchRequired != null) {
properties.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0);
}
if (tuple.parseNoExponent != null) {
properties.setParseNoExponent(tuple.parseNoExponent != 0);
static void propertiesFromTuple(DataDrivenNumberFormatTestData tuple, Properties properties) {
if (tuple.minIntegerDigits != null) {
properties.setMinimumIntegerDigits(tuple.minIntegerDigits);
}
if (tuple.maxIntegerDigits != null) {
properties.setMaximumIntegerDigits(tuple.maxIntegerDigits);
}
if (tuple.minFractionDigits != null) {
properties.setMinimumFractionDigits(tuple.minFractionDigits);
}
if (tuple.maxFractionDigits != null) {
properties.setMaximumFractionDigits(tuple.maxFractionDigits);
}
if (tuple.currency != null) {
properties.setCurrency(tuple.currency);
}
if (tuple.minGroupingDigits != null) {
properties.setMinimumGroupingDigits(tuple.minGroupingDigits);
}
if (tuple.useSigDigits != null) {
// TODO
}
if (tuple.minSigDigits != null) {
properties.setMinimumSignificantDigits(tuple.minSigDigits);
}
if (tuple.maxSigDigits != null) {
properties.setMaximumSignificantDigits(tuple.maxSigDigits);
}
if (tuple.useGrouping != null && tuple.useGrouping == 0) {
properties.setGroupingSize(-1);
properties.setSecondaryGroupingSize(-1);
}
if (tuple.multiplier != null) {
properties.setMultiplier(new BigDecimal(tuple.multiplier));
}
if (tuple.roundingIncrement != null) {
properties.setRoundingIncrement(new BigDecimal(tuple.roundingIncrement.toString()));
}
if (tuple.formatWidth != null) {
properties.setFormatWidth(tuple.formatWidth);
}
if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
properties.setPadString(tuple.padCharacter.toString());
}
if (tuple.useScientific != null) {
properties.setMinimumExponentDigits(
tuple.useScientific != 0 ? 1 : Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS);
}
if (tuple.grouping != null) {
properties.setGroupingSize(tuple.grouping);
}
if (tuple.grouping2 != null) {
properties.setSecondaryGroupingSize(tuple.grouping2);
}
if (tuple.roundingMode != null) {
properties.setRoundingMode(RoundingMode.valueOf(tuple.roundingMode));
}
if (tuple.currencyUsage != null) {
properties.setCurrencyUsage(tuple.currencyUsage);
}
if (tuple.minimumExponentDigits != null) {
properties.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue());
}
if (tuple.exponentSignAlwaysShown != null) {
properties.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0);
}
if (tuple.decimalSeparatorAlwaysShown != null) {
properties.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0);
}
if (tuple.padPosition != null) {
properties.setPadPosition(PadPosition.fromOld(tuple.padPosition));
}
if (tuple.positivePrefix != null) {
properties.setPositivePrefix(tuple.positivePrefix);
}
if (tuple.positiveSuffix != null) {
properties.setPositiveSuffix(tuple.positiveSuffix);
}
if (tuple.negativePrefix != null) {
properties.setNegativePrefix(tuple.negativePrefix);
}
if (tuple.negativeSuffix != null) {
properties.setNegativeSuffix(tuple.negativeSuffix);
}
if (tuple.localizedPattern != null) {
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(tuple.locale);
String converted = PatternString.convertLocalized(tuple.localizedPattern, symbols, false);
PatternString.parseToExistingProperties(converted, properties);
}
if (tuple.lenient != null) {
properties.setParseMode(tuple.lenient == 0 ? ParseMode.STRICT : ParseMode.LENIENT);
}
if (tuple.parseIntegerOnly != null) {
properties.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
}
if (tuple.parseCaseSensitive != null) {
properties.setParseCaseSensitive(tuple.parseCaseSensitive != 0);
}
if (tuple.decimalPatternMatchRequired != null) {
properties.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0);
}
if (tuple.parseNoExponent != null) {
properties.setParseNoExponent(tuple.parseNoExponent != 0);
}
}
private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU60 =
new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
@Override
public Character Id() {
return 'Q';
}
/**
* Runs a single formatting test. On success, returns null. On failure, returns the error.
* This implementation just returns null. Subclasses should override.
*
* @param tuple contains the parameters of the format test.
*/
@Override
public String format(DataDrivenNumberFormatTestData tuple) {
String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
ULocale locale = (tuple.locale == null) ? ULocale.ENGLISH : tuple.locale;
Properties properties =
PatternString.parseToProperties(
pattern,
tuple.currency != null
? PatternString.IGNORE_ROUNDING_ALWAYS
: PatternString.IGNORE_ROUNDING_NEVER);
propertiesFromTuple(tuple, properties);
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, null);
LocalizedNumberFormatter fmt = NumberFormatterImpl.fromMacros(macros).locale(locale);
Number number = toNumber(tuple.format);
String expected = tuple.output;
String actual = fmt.format(number).toString();
if (!expected.equals(actual)) {
return "Expected \"" + expected + "\", got \"" + actual + "\"";
}
return null;
}
};
@Test
@Ignore
public void TestDataDrivenICU58() {
// Android can't access DecimalFormat_ICU58 for testing (ticket #13283).
if (TestUtil.getJavaVendor() == TestUtil.JavaVendor.Android) return;
@ -787,14 +830,22 @@ public class NumberFormatDataDrivenTest {
}
@Test
@Ignore
public void TestDataDrivenJDK() {
DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
"numberformattestspecification.txt", JDK);
}
@Test
public void TestDataDrivenShane() {
@Ignore
public void TestDataDrivenICU59() {
DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
"numberformattestspecification.txt", Shane);
"numberformattestspecification.txt", ICU59);
}
@Test
public void TestDataDrivenICU60() {
DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
"numberformattestspecification.txt", ICU60);
}
}

View File

@ -76,7 +76,7 @@ public class NumberFormatRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
// or this (with changes to fr_CH per cldrbug:9370):
//nf.setGroupingUsed(false);
// so they are done in DateFormat.setNumberFormat
// create the DateFormat
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, loc);
@ -185,7 +185,8 @@ public class NumberFormatRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
String result = format.format(data);
assertEquals("Deserialization new version should read old version", expected[i], result);
} catch (Exception e) {
warnln("FAIL: " + e.getMessage());
e.printStackTrace();
warnln("FAIL: " + e);
}
}
}

View File

@ -50,7 +50,6 @@ import com.ibm.icu.text.CompactDecimalFormat;
import com.ibm.icu.text.CurrencyPluralInfo;
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.DecimalFormat.PropertySetter;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.DecimalFormat_ICU58;
import com.ibm.icu.text.DisplayContext;
@ -500,13 +499,13 @@ public class NumberFormatTest extends TestFmwk {
// currency format using currency ISO name, such as "USD",
// currency format using plural name, such as "US dollars".
// for US locale
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1234.56", "$1,234.56", "USD1,234.56", "US dollars1,234.56"},
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD1,234.56", "-US dollars1,234.56"},
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollars1.00"},
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1234.56", "$1,234.56", "USD 1,234.56", "US dollars 1,234.56"},
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD 1,234.56", "-US dollars 1,234.56"},
{"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1", "$1.00", "USD 1.00", "US dollars 1.00"},
// for CHINA locale
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1234.56", "\uFFE51,234.56", "CNY1,234.56", "\u4EBA\u6C11\u5E011,234.56"},
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "-1234.56", "(\uFFE51,234.56)", "(CNY1,234.56)", "(\u4EBA\u6C11\u5E011,234.56)"},
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1", "\uFFE51.00", "CNY1.00", "\u4EBA\u6C11\u5E011.00"}
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1234.56", "\uFFE51,234.56", "CNY 1,234.56", "\u4EBA\u6C11\u5E01 1,234.56"},
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "-1234.56", "(\uFFE51,234.56)", "(CNY 1,234.56)", "(\u4EBA\u6C11\u5E01 1,234.56)"},
{"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1", "\uFFE51.00", "CNY 1.00", "\u4EBA\u6C11\u5E01 1.00"}
};
String doubleCurrencyStr = "\u00A4\u00A4";
@ -536,7 +535,7 @@ public class NumberFormatTest extends TestFmwk {
// 'j' number of currency sign.
String currencyFormatResult = DATA[i][2+j];
if (!s.equals(currencyFormatResult)) {
errln("FAIL format: Expected " + currencyFormatResult);
errln("FAIL format: Expected " + currencyFormatResult + " but got " + s);
}
try {
// mix style parsing
@ -712,13 +711,13 @@ public class NumberFormatTest extends TestFmwk {
// format result using CURRENCYSTYLE,
// format result using ISOCURRENCYSTYLE,
// format result using PLURALCURRENCYSTYLE,
{"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollars"},
{"en_US", "1234.56", "USD", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
{"en_US", "-1234.56", "USD", "-$1,234.56", "-USD1,234.56", "-1,234.56 US dollars"},
{"zh_CN", "1", "USD", "US$1.00", "USD1.00", "1.00美元"},
{"zh_CN", "1234.56", "USD", "US$1,234.56", "USD1,234.56", "1,234.56美元"},
{"zh_CN", "1", "CNY", "¥1.00", "CNY1.00", "1.00人民币"},
{"zh_CN", "1234.56", "CNY", "¥1,234.56", "CNY1,234.56", "1,234.56人民币"},
{"en_US", "1", "USD", "$1.00", "USD 1.00", "1.00 US dollars"},
{"en_US", "1234.56", "USD", "$1,234.56", "USD 1,234.56", "1,234.56 US dollars"},
{"en_US", "-1234.56", "USD", "-$1,234.56", "-USD 1,234.56", "-1,234.56 US dollars"},
{"zh_CN", "1", "USD", "US$1.00", "USD 1.00", "1.00 美元"},
{"zh_CN", "1234.56", "USD", "US$1,234.56", "USD 1,234.56", "1,234.56 美元"},
{"zh_CN", "1", "CNY", "¥1.00", "CNY 1.00", "1.00 人民币"},
{"zh_CN", "1234.56", "CNY", "¥1,234.56", "CNY 1,234.56", "1,234.56 人民币"},
{"ru_RU", "1", "RUB", "1,00 \u20BD", "1,00 RUB", "1,00 российского рубля"},
{"ru_RU", "2", "RUB", "2,00 \u20BD", "2,00 RUB", "2,00 российского рубля"},
{"ru_RU", "5", "RUB", "5,00 \u20BD", "5,00 RUB", "5,00 российского рубля"},
@ -957,7 +956,7 @@ public class NumberFormatTest extends TestFmwk {
1234.56, "\u00A51,235"); // Yen
expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
1234.56, "CHF 1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
expectCurrency(fmt, Currency.getInstance(Locale.US),
1234.56, "$1,234.56");
@ -1727,7 +1726,7 @@ public class NumberFormatTest extends TestFmwk {
ULocale locale = new ULocale("th_TH@currency=QQQ");
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
String result = format.format(12.34f);
if (!"QQQ12.34".equals(result)) {
if (!"QQQ 12.34".equals(result)) {
errln("got unexpected currency: " + result);
}
}
@ -2255,13 +2254,13 @@ public class NumberFormatTest extends TestFmwk {
nf.setCurrency(Currency.getInstance(new Locale("fr", "ch", "")));
StringBuffer buffer2 = new StringBuffer();
nf.format(amount, buffer2, cp);
assertEquals("CHF35.47", "CHF35.47", buffer2.toString());
assertEquals("CHF 35.47", "CHF 35.47", buffer2.toString());
assertEquals("cp begin", 0, cp.getBeginIndex());
assertEquals("cp end", 3, cp.getEndIndex());
StringBuffer buffer20 = new StringBuffer();
nf.format(negAmount, buffer20, cp);
assertEquals("-CHF34.57", "-CHF34.57", buffer20.toString());
assertEquals("-CHF 34.57", "-CHF 34.57", buffer20.toString());
assertEquals("cp begin", 1, cp.getBeginIndex());
assertEquals("cp end", 4, cp.getEndIndex());
@ -2296,17 +2295,17 @@ public class NumberFormatTest extends TestFmwk {
plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "ch"), NumberFormat.PLURALCURRENCYSTYLE);
StringBuffer buffer7 = new StringBuffer();
plCurrencyFmt.format(amount, buffer7, cp);
assertEquals("35.47スイス フラン", "35.47スイス フラン", buffer7.toString());
assertEquals("cp begin", 5, cp.getBeginIndex());
assertEquals("cp end", 12, cp.getEndIndex());
assertEquals("35.47 スイス フラン", "35.47 スイス フラン", buffer7.toString());
assertEquals("cp begin", 6, cp.getBeginIndex());
assertEquals("cp end", 13, cp.getEndIndex());
// PLURALCURRENCYSTYLE for non-ASCII.
plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "de"), NumberFormat.PLURALCURRENCYSTYLE);
StringBuffer buffer8 = new StringBuffer();
plCurrencyFmt.format(negAmount, buffer8, cp);
assertEquals("-34.57ユーロ", "-34.57ユーロ", buffer8.toString());
assertEquals("cp begin", 6, cp.getBeginIndex());
assertEquals("cp end", 9, cp.getEndIndex());
assertEquals("-34.57 ユーロ", "-34.57 ユーロ", buffer8.toString());
assertEquals("cp begin", 7, cp.getBeginIndex());
assertEquals("cp end", 10, cp.getEndIndex());
nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getCurrencyInstance(Locale.JAPAN);
nf.setCurrency(Currency.getInstance(new Locale("ja", "jp")));
@ -2320,9 +2319,9 @@ public class NumberFormatTest extends TestFmwk {
plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "ch"), NumberFormat.PLURALCURRENCYSTYLE);
StringBuffer buffer10 = new StringBuffer();
plCurrencyFmt.format(negAmount, buffer10, cp);
assertEquals("-34.57スイス フラン", "-34.57スイス フラン", buffer10.toString());
assertEquals("cp begin", 6, cp.getBeginIndex());
assertEquals("cp end", 13, cp.getEndIndex());
assertEquals("-34.57 スイス フラン", "-34.57 スイス フラン", buffer10.toString());
assertEquals("cp begin", 7, cp.getBeginIndex());
assertEquals("cp end", 14, cp.getEndIndex());
// Nagative value with PLURALCURRENCYSTYLE, Arabic digits.
nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getCurrencyInstance(new Locale("ar", "eg"));
@ -2362,11 +2361,11 @@ public class NumberFormatTest extends TestFmwk {
public void TestRoundingPattern() {
class TestRoundingPatternItem {
String pattern;
double roundingIncrement;
BigDecimal roundingIncrement;
double testCase;
String expected;
TestRoundingPatternItem(String pattern, double roundingIncrement, double testCase, String expected) {
TestRoundingPatternItem(String pattern, BigDecimal roundingIncrement, double testCase, String expected) {
this.pattern = pattern;
this.roundingIncrement = roundingIncrement;
this.testCase = testCase;
@ -2375,13 +2374,12 @@ public class NumberFormatTest extends TestFmwk {
};
TestRoundingPatternItem []tests = {
new TestRoundingPatternItem("##0.65", 0.65, 1.234, "1.30"),
new TestRoundingPatternItem("#50", 50.0, 1230, "1250")
new TestRoundingPatternItem("##0.65", new BigDecimal("0.65"), 1.234, "1.30"),
new TestRoundingPatternItem("#50", new BigDecimal("50"), 1230, "1250")
};
DecimalFormat df = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
String result;
BigDecimal bd;
for (int i = 0; i < tests.length; i++) {
df.applyPattern(tests[i].pattern);
@ -2391,9 +2389,7 @@ public class NumberFormatTest extends TestFmwk {
errln("String Pattern Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
}
bd = new BigDecimal(tests[i].roundingIncrement);
df.setRoundingIncrement(bd);
df.setRoundingIncrement(tests[i].roundingIncrement);
result = df.format(tests[i].testCase);
@ -4130,7 +4126,7 @@ public class NumberFormatTest extends TestFmwk {
// * TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
// * CAD rounds to .05 in the cash style only.
for (int i = 0; i < 2; i++) {
String original_expected = "PKR124";
String original_expected = "PKR 124";
DecimalFormat custom = null;
if (i == 0) {
custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=PKR"),
@ -4153,7 +4149,7 @@ public class NumberFormatTest extends TestFmwk {
}
String cash_currency = custom.format(123.567);
String cash_currency_expected = "PKR124";
String cash_currency_expected = "PKR 124";
assertEquals("Test Currency Context", cash_currency_expected, cash_currency);
}
@ -4195,7 +4191,7 @@ public class NumberFormatTest extends TestFmwk {
fmt2.setCurrency(Currency.getInstance("PKR"));
String PKR_changed = fmt2.format(123.567);
String PKR_changed_expected = "PKR124";
String PKR_changed_expected = "PKR 124";
assertEquals("Test Currency Context", PKR_changed_expected, PKR_changed);
}
}
@ -4744,7 +4740,7 @@ public class NumberFormatTest extends TestFmwk {
fmt.setDecimalFormatSymbols(symbols);
fmt.applyPattern("#,##0.0#");
assertEquals("Custom decimal and grouping separator string with multiple characters",
fmt.format(1234567.89), "(1)^^(2)(3)(4)^^(5)(6)(7)~~(8)(9)");
"(1)^^(2)(3)(4)^^(5)(6)(7)~~(8)(9)", fmt.format(1234567.89));
// Digits starting at U+1D7CE MATHEMATICAL BOLD DIGIT ZERO
// These are all single code points, so parsing will work.
@ -4917,7 +4913,7 @@ public class NumberFormatTest extends TestFmwk {
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.applyPattern("¤¤¤ 0");
String result = df.getPositivePrefix();
assertEquals("Triple-currency should give long name on getPositivePrefix", "US dollars ", result);
assertEquals("Triple-currency should give long name on getPositivePrefix", "US dollar ", result);
}
@Test
@ -5263,7 +5259,7 @@ public class NumberFormatTest extends TestFmwk {
symbols.setCurrencySymbol("#");
df.setDecimalFormatSymbols(symbols);
String actual = df.format(123);
assertEquals("Should use '#' instad of '$'", "#123.00", actual);
assertEquals("Should use '#' instad of '$'", "# 123.00", actual);
}
@Test
@ -5478,9 +5474,9 @@ public class NumberFormatTest extends TestFmwk {
df.setMaximumFractionDigits(3);
expect2(df, 35.0, "$35.000");
df.setMinimumFractionDigits(-1);
expect2(df, 35.0, "$35");
df.setMaximumFractionDigits(-1);
expect2(df, 35.0, "$35.00");
df.setMaximumFractionDigits(1);
expect2(df, 35.0, "$35.0");
}
@Test
@ -5637,46 +5633,6 @@ public class NumberFormatTest extends TestFmwk {
}
}
@Test
public void testSignificantDigitsMode() {
String[][] allExpected = {
{"12340.0", "12340.0", "12340.0"},
{"1234.0", "1234.0", "1234.0"},
{"123.4", "123.4", "123.4"},
{"12.34", "12.34", "12.34"},
{"1.234", "1.23", "1.23"},
{"0.1234", "0.12", "0.123"},
{"0.01234", "0.01", "0.0123"},
{"0.001234", "0.00", "0.00123"}
};
DecimalFormat df = new DecimalFormat();
df.setMinimumFractionDigits(1);
df.setMaximumFractionDigits(2);
df.setMinimumSignificantDigits(3);
df.setMaximumSignificantDigits(4);
df.setGroupingUsed(false);
SignificantDigitsMode[] modes = new SignificantDigitsMode[] {
SignificantDigitsMode.OVERRIDE_MAXIMUM_FRACTION,
SignificantDigitsMode.RESPECT_MAXIMUM_FRACTION,
SignificantDigitsMode.ENSURE_MINIMUM_SIGNIFICANT
};
for (double d = 12340.0, i=0; d > 0.001; d /= 10, i++) {
for (int j=0; j<modes.length; j++) {
SignificantDigitsMode mode = modes[j];
df.setSignificantDigitsMode(mode);
String expected = allExpected[(int)i][j];
String actual = df.format(d);
assertEquals("Significant digits mode getter is broken",
mode, df.getSignificantDigitsMode());
assertEquals("Significant digits output differs for "+i+", "+j,
expected, actual);
}
}
}
@Test
public void testParseNoExponent() throws ParseException {
DecimalFormat df = new DecimalFormat();

View File

@ -82,13 +82,13 @@ fpc: - 1234.56/JPY "¥1,235" 1235/JPY
# ISO codes that overlap display names (QQQ vs. Q)
# fake ISO code is not longer supported
# fpc: - 123/QQQ "QQQ123.00" 123/QQQ # QQQ is fake
fpc: - 123/GTQ "GTQ123.00" 123/GTQ
fpc: - 123/GTQ "GTQ 123.00" 123/GTQ
# ChoiceFormat-based display names
fpc: - 1/INR "₹1.00" 1/INR
fpc: - 2/INR "₹2.00" 2/INR
# Display names with shared prefix (YDD vs. Y)
fpc: - 100/YDD "YDD100.00" 100/YDD
fpc: - 100/YDD "YDD 100.00" 100/YDD
fpc: - 100/CNY "CN¥100.00" 100/CNY
# Lenient Tests

View File

@ -161,7 +161,7 @@ public class NumberRegressionTests extends TestFmwk {
try {
logln(df.format(123, sBuf, fp).toString());
} catch (Exception foo) {
errln("Test for bug 4088503 failed.");
errln("Test for bug 4088503 failed: " + foo);
}
}
@ -963,6 +963,7 @@ public class NumberRegressionTests extends TestFmwk {
Locale.setDefault(Locale.US);
DecimalFormat df = new DecimalFormat();
df.setPositivePrefix("+");
df.setNegativePrefix("-");
double d = -0.0;
logln("pattern: \"" + df.toPattern() + "\"");
StringBuffer buffer = new StringBuffer();
@ -999,6 +1000,7 @@ public class NumberRegressionTests extends TestFmwk {
{
Locale[] locales = NumberFormat.getAvailableLocales();
outer:
for (int i = 0; i < locales.length; i++) {
ICUResourceBundle rb = (ICUResourceBundle)ICUResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,locales[i]);
@ -1054,11 +1056,20 @@ public class NumberRegressionTests extends TestFmwk {
String result2 = fmt2.format(1.111);
// NOTE: en_IN is a special case (ChoiceFormat currency display name)
if (!result1.equals(result2) &&
!locales[i].toString().equals("en_IN")) {
errln("Results for " + locales[i] + " differ: " +
result1 + " vs " + result2);
// Currency spacing may have been added by the real DecimalFormat. Account for that here.
if (!result1.equals(result2)) {
if (result1.length() == result2.length() + 1) {
inner:
for (int k=0; k<result2.length(); k++) {
if (result1.charAt(k) != result2.charAt(k)) {
if (result1.charAt(k) == '\u00A0') {
continue outer; // currency spacing OK
}
break inner;
}
}
}
errln("Results for " + locales[i] + " differ: " + result1 + " vs " + result2);
}
}
}
@ -1483,9 +1494,9 @@ public class NumberRegressionTests extends TestFmwk {
fmt.applyPattern("\u00A4#.00");
sym.setCurrencySymbol("usd");
fmt.setDecimalFormatSymbols(sym);
if (!fmt.format(12.5).equals("usd12.50")) {
if (!fmt.format(12.5).equals("usd 12.50")) {
errln("FAIL: 12.5 x (currency=usd) -> " + fmt.format(12.5) +
", exp usd12.50");
", exp usd 12.50");
}
if (!fmt.getPositivePrefix().equals("usd")) {
errln("FAIL: (currency=usd).getPositivePrefix -> " +
@ -1496,9 +1507,9 @@ public class NumberRegressionTests extends TestFmwk {
fmt.applyPattern("\u00A4\u00A4#.00");
sym.setInternationalCurrencySymbol("DOL");
fmt.setDecimalFormatSymbols(sym);
if (!fmt.format(12.5).equals("DOL12.50")) {
if (!fmt.format(12.5).equals("DOL 12.50")) {
errln("FAIL: 12.5 x (intlcurrency=DOL) -> " + fmt.format(12.5) +
", exp DOL12.50");
", exp DOL 12.50");
}
if (!fmt.getPositivePrefix().equals("DOL")) {
errln("FAIL: (intlcurrency=DOL).getPositivePrefix -> " +

View File

@ -37,7 +37,6 @@ import com.ibm.icu.impl.number.formatters.CurrencyFormat.CurrencyStyle;
import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.util.Currency;
@ -306,11 +305,6 @@ public class PropertiesTest {
RoundingMode[] values = RoundingMode.values();
return values[seed % values.length];
} else if (type == SignificantDigitsMode.class) {
if (seed == 0) return null;
SignificantDigitsMode[] values = SignificantDigitsMode.values();
return values[seed % values.length];
} else {
fail("Don't know how to handle type " + type + ". Please add it to getSampleValueForType().");
return null;

View File

@ -1,134 +0,0 @@
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.dev.test.number;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.FormatQuantity4;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
public class RounderTest {
@Test
public void testSignificantDigitsRounder() {
Object[][][][] cases = {
{
{{1, -1}, {0, 2}, {2, 4}}, // minInt, maxInt, minFrac, maxFrac, minSig, maxSig
{
{0.0, "0.0", "0.0", "0"},
{0.054321, "0.05432", "0.05", "0.054"},
{0.54321, "0.5432", "0.54", "0.54"},
{1.0, "1.0", "1.0", "1"},
{5.4321, "5.432", "5.43", "5.43"},
{10.0, "10", "10", "10"},
{11.0, "11", "11", "11"},
{100.0, "100", "100", "100"},
{100.23, "100.2", "100.2", "100.2"},
{543210.0, "543200", "543200", "543200"},
}
},
{
{{1, -1}, {0, 0}, {2, -1}}, // minInt, maxInt, minFrac, maxFrac, minSig, maxSig
{
{0.0, "0.0", "0", "0"},
{0.054321, "0.054321", "0", "0.054"},
{0.54321, "0.54321", "1", "0.54"},
{1.0, "1.0", "1", "1"},
{5.4321, "5.4321", "5", "5.4"},
{10.0, "10", "10", "10"},
{11.0, "11", "11", "11"},
{100.0, "100", "100", "100"},
{100.23, "100.23", "100", "100"},
{543210.0, "543210", "543210", "543210"},
}
},
{
{{0, 2}, {1, 2}, {3, 3}}, // minInt, maxInt, minFrac, maxFrac, minSig, maxSig
{
{0.0, ".000", ".00", ".0"},
{0.054321, ".0543", ".05", ".0543"},
{0.54321, ".543", ".54", ".543"},
{1.0, "1.00", "1.00", "1.0"},
{5.4321, "5.43", "5.43", "5.43"},
{10.0, "10.0", "10.0", "10.0"},
{11.0, "11.0", "11.0", "11.0"},
{100.0, "00.0", "00.0", "00.0"},
{100.23, "00.2", "00.2", "00.2"},
{543210.0, "10.0", "10.0", "10.0"}
}
}
};
int caseNumber = 0;
for (Object[][][] cas : cases) {
int minInt = (Integer) cas[0][0][0];
int maxInt = (Integer) cas[0][0][1];
int minFrac = (Integer) cas[0][1][0];
int maxFrac = (Integer) cas[0][1][1];
int minSig = (Integer) cas[0][2][0];
int maxSig = (Integer) cas[0][2][1];
Properties properties = new Properties();
FormatQuantity4 fq = new FormatQuantity4();
properties.setMinimumIntegerDigits(minInt);
properties.setMaximumIntegerDigits(maxInt);
properties.setMinimumFractionDigits(minFrac);
properties.setMaximumFractionDigits(maxFrac);
properties.setMinimumSignificantDigits(minSig);
properties.setMaximumSignificantDigits(maxSig);
int runNumber = 0;
for (Object[] run : cas[1]) {
double input = (Double) run[0];
String expected1 = (String) run[1];
String expected2 = (String) run[2];
String expected3 = (String) run[3];
properties.setSignificantDigitsMode(SignificantDigitsMode.OVERRIDE_MAXIMUM_FRACTION);
fq.setToDouble(input);
SignificantDigitsRounder.getInstance(properties).apply(fq);
assertEquals(
"Case " + caseNumber + ", run " + runNumber + ", mode 0: " + fq,
expected1,
formatQuantityToString(fq));
properties.setSignificantDigitsMode(SignificantDigitsMode.RESPECT_MAXIMUM_FRACTION);
fq.setToDouble(input);
SignificantDigitsRounder.getInstance(properties).apply(fq);
assertEquals(
"Case " + caseNumber + ", run " + runNumber + ", mode 1: " + fq,
expected2,
formatQuantityToString(fq));
properties.setSignificantDigitsMode(SignificantDigitsMode.ENSURE_MINIMUM_SIGNIFICANT);
fq.setToDouble(input);
SignificantDigitsRounder.getInstance(properties).apply(fq);
assertEquals(
"Case " + caseNumber + ", run " + runNumber + ", mode 2: " + fq,
expected3,
formatQuantityToString(fq));
runNumber++;
}
caseNumber++;
}
}
private String formatQuantityToString(FormatQuantity fq) {
StringBuilder sb = new StringBuilder();
int udm = fq.getUpperDisplayMagnitude();
int ldm = fq.getLowerDisplayMagnitude();
if (udm == -1) sb.append('.');
for (int m = udm; m >= ldm; m--) {
sb.append(fq.getDigit(m));
if (m == 0 && m > ldm) sb.append('.');
}
return sb.toString();
}
}