/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.java.text;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Currency;
import java.util.Locale;
public class NumberFormatTest extends junit.framework.TestCase {
// NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls doubleValue for
// custom Number subclasses.
public void test_custom_Number_gets_longValue() throws Exception {
class MyNumber extends Number {
public byte byteValue() { throw new UnsupportedOperationException(); }
public double doubleValue() { return 123; }
public float floatValue() { throw new UnsupportedOperationException(); }
public int intValue() { throw new UnsupportedOperationException(); }
public long longValue() { throw new UnsupportedOperationException(); }
public short shortValue() { throw new UnsupportedOperationException(); }
public String toString() { throw new UnsupportedOperationException(); }
}
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
assertEquals("123", nf.format(new MyNumber()));
}
// NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls longValue for
// any BigInteger with a bitLength strictly less than 64.
public void test_small_BigInteger_gets_longValue() throws Exception {
class MyNumberFormat extends NumberFormat {
public StringBuffer format(double value, StringBuffer b, FieldPosition f) {
b.append("double");
return b;
}
public StringBuffer format(long value, StringBuffer b, FieldPosition f) {
b.append("long");
return b;
}
public Number parse(String string, ParsePosition p) {
throw new UnsupportedOperationException();
}
}
NumberFormat nf = new MyNumberFormat();
assertEquals("long", nf.format(BigInteger.valueOf(Long.MAX_VALUE)));
assertEquals("double", nf.format(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)));
assertEquals("long", nf.format(BigInteger.valueOf(Long.MIN_VALUE)));
assertEquals("double", nf.format(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE)));
}
public void test_getIntegerInstance_ar() throws Exception {
// Previous versions of android use just the positive format string (ICU4C) although now we
// use '<positive_format>;<negative_format>' because of ICU4J denormalization.
NumberFormat numberFormat = NumberFormat.getNumberInstance(new Locale("ar"));
String patternNI = ((DecimalFormat) numberFormat).toPattern();
assertTrue("#,##0.###;-#,##0.###".equals(patternNI) || "#,##0.###".equals(patternNI));
NumberFormat integerFormat = NumberFormat.getIntegerInstance(new Locale("ar"));
String patternII = ((DecimalFormat) integerFormat).toPattern();
assertTrue("#,##0;-#,##0".equals(patternII) || "#,##0".equals(patternII));
}
/* J2ObjC: The Arabic symbols don't appear to be available on macOS.
public void test_numberLocalization() throws Exception {
Locale arabic = new Locale("ar");
NumberFormat nf = NumberFormat.getNumberInstance(arabic);
assertEquals('\u0660', new DecimalFormatSymbols(arabic).getZeroDigit());
assertEquals("١٬٢٣٤٬٥٦٧٬٨٩٠", nf.format(1234567890));
}*/
// Formatting percentages is confusing but deliberate.
// Ensure we don't accidentally "fix" this.
// https://code.google.com/p/android/issues/detail?id=10333
public void test_10333() throws Exception {
NumberFormat nf = NumberFormat.getPercentInstance(Locale.US);
assertEquals("15%", nf.format(0.15));
assertEquals("1,500%", nf.format(15));
try {
nf.format("15");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testPercentageRounding() throws Exception {
NumberFormat nf = NumberFormat.getPercentInstance(Locale.US);
assertEquals("15%", nf.format(0.149));
assertEquals("14%", nf.format(0.142));
nf.setRoundingMode(RoundingMode.UP);
assertEquals("15%", nf.format(0.142));
nf.setRoundingMode(RoundingMode.DOWN);
assertEquals("14%", nf.format(0.149));
nf.setMaximumFractionDigits(1);
// J2ObjC: Was a bad test using 0.149 as input because floating point representation might
// be less than 0.149 and round down to 14.8%.
assertEquals("14.9%", nf.format(0.1491));
}
// https://code.google.com/p/android/issues/detail?id=62269
public void test_62269() throws Exception {
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
try {
nf.parse(null);
fail();
} catch (NullPointerException expected) {
}
}
public void test_nullLocales() {
try {
NumberFormat.getInstance(null);
fail();
} catch (NullPointerException expected) {}
try {
NumberFormat.getIntegerInstance(null);
fail();
} catch (NullPointerException expected) {}
try {
NumberFormat.getCurrencyInstance(null);
fail();
} catch (NullPointerException expected) {}
try {
NumberFormat.getPercentInstance(null);
fail();
} catch (NullPointerException expected) {}
try {
NumberFormat.getNumberInstance(null);
fail();
} catch (NullPointerException expected) {}
}
// https://code.google.com/p/android/issues/detail?id=79925\
// When switching currency after having initialised a DecimalFormat instance to a currency,
// the symbols are missing.
public void test_issue79925() {
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US);
nf.setCurrency(Currency.getInstance("EUR"));
assertEquals("€50.00", nf.format(50.0));
DecimalFormatSymbols decimalFormatSymbols = ((DecimalFormat) nf).getDecimalFormatSymbols();
decimalFormatSymbols.setCurrencySymbol("");
((DecimalFormat) nf).setDecimalFormatSymbols(decimalFormatSymbols);
assertEquals("50.00", nf.format(50.0));
nf.setCurrency(Currency.getInstance("SGD"));
assertEquals("SGD50.00", nf.format(50.0));
nf.setCurrency(Currency.getInstance("SGD"));
assertEquals("SGD50.00", nf.format(50.00));
nf.setCurrency(Currency.getInstance("USD"));
assertEquals("$50.00", nf.format(50.0));
nf.setCurrency(Currency.getInstance("SGD"));
assertEquals("SGD50.00", nf.format(50.0));
}
// Test to ensure explicitly setting a currency symbol will overwrite the defaults.
public void test_customCurrencySymbol() {
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US);
DecimalFormatSymbols dfs = ((DecimalFormat) nf).getDecimalFormatSymbols();
dfs.setCurrencySymbol("SPECIAL");
((DecimalFormat) nf).setDecimalFormatSymbols(dfs);
assertEquals("SPECIAL3.14", nf.format(3.14));
// Setting the currency again should reset the symbols.
nf.setCurrency(Currency.getInstance("USD"));
assertEquals("$3.14", nf.format(3.14));
// Setting it back again should work.
dfs.setCurrencySymbol("NEW");
((DecimalFormat) nf).setDecimalFormatSymbols(dfs);
assertEquals("NEW3.14", nf.format(3.14));
}
// Test to ensure currency formatting from specified locale works.
public void test_currencyFromLocale() {
// French locale formats with "," as separator and Euro symbol after a non-breaking space.
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.FRANCE);
assertEquals("50,00\u00a0€", nf.format(50));
// British locale uses pound sign with no spacing.
nf = NumberFormat.getCurrencyInstance(Locale.UK);
assertEquals("£50.00", nf.format(50));
}
// Test the currency symbol is correctly taken from ICU. Verifies that the fractional digits
// are not updated because DecimalFormat.setCurrency agrees not to change it.
public void test_setCurrency() throws Exception {
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US);
// The Armenian Dram is a special case where the fractional digits are 0.
Currency amd = Currency.getInstance("AMD");
assertEquals(0, amd.getDefaultFractionDigits());
// Armenian Dram ISO 4217 code.
nf.setCurrency(amd);
assertEquals(2, nf.getMinimumFractionDigits()); // Check DecimalFormat has not taken the
assertEquals(2, nf.getMaximumFractionDigits()); // currency specific fractional digits.
assertEquals("AMD50.00", nf.format(50.00));
// Try and explicitly request fractional digits for the specified currency.
nf.setMaximumFractionDigits(amd.getDefaultFractionDigits());
assertEquals("AMD50", nf.format(50.00));
nf = NumberFormat.getCurrencyInstance(Locale.US);
// Euro sign.
nf.setCurrency(Currency.getInstance("EUR"));
assertEquals("€50.00", nf.format(50.00));
// Japanese Yen symbol.
nf.setCurrency(Currency.getInstance("JPY"));
assertEquals("¥50.00", nf.format(50.00));
// Swiss Franc ISO 4217 code.
nf.setCurrency(Currency.getInstance("CHF"));
assertEquals("CHF50.00", nf.format(50.00));
}
// Test the setting of locale specific patterns which have different fractional digits.
public void test_currencyWithPatternDigits() throws Exception {
// Japanese Yen 0 fractional digits.
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.JAPAN);
String result = nf.format(50.00);
// Allow either full-width (0xFFE5) or regular width yen sign (0xA5).
assertTrue(result.equals("¥50") || result.equals("¥50"));
// Armenian Dram 0 fractional digits.
nf = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("hy-AM"));
assertEquals("֏\u00a050", nf.format(50.00));
// Swiss Francs 2 fractional digits.
nf = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("de-CH"));
assertEquals("CHF\u00a050.00", nf.format(50.00));
}
// http://b/28893763
public void test_setCurrency_leavesFractionDigitsUntouched() {
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US);
format.setMinimumFractionDigits(0);
format.setCurrency(Currency.getInstance("USD"));
assertEquals("$10", format.format(10d));
}
}