1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.text;
18
19import java.math.BigDecimal;
20import java.math.BigInteger;
21import java.math.RoundingMode;
22import java.text.DecimalFormat;
23import java.text.DecimalFormatSymbols;
24import java.text.FieldPosition;
25import java.text.NumberFormat;
26import java.text.ParsePosition;
27import java.util.Currency;
28import java.util.Locale;
29
30public class DecimalFormatTest extends junit.framework.TestCase {
31    public void test_exponentSeparator() throws Exception {
32        DecimalFormat df = new DecimalFormat("0E0");
33        assertEquals("1E4", df.format(12345.));
34
35        DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
36        dfs.setExponentSeparator("-useless-api-");
37        df.setDecimalFormatSymbols(dfs);
38        assertEquals("1-useless-api-4", df.format(12345.));
39    }
40
41    public void test_setMaximumFractionDigitsAffectsRoundingMode() throws Exception {
42        DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
43        df.setMaximumFractionDigits(0);
44        df.setRoundingMode(RoundingMode.HALF_UP);
45        assertEquals("-0", df.format(-0.2));
46        df.setMaximumFractionDigits(1);
47        assertEquals("-0.2", df.format(-0.2));
48    }
49
50    // Android fails this test, truncating to 127 digits.
51    public void test_setMaximumIntegerDigits() throws Exception {
52        NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US);
53        numberFormat.setGroupingUsed(false);
54        numberFormat.setMinimumIntegerDigits(400);
55        // The RI's documentation suggests that the int should be formatted to 309 characters --
56        // a magic number they don't explain -- but the BigInteger should be formatted to the 400
57        // characters we asked for. In practice, the RI uses 309 in both cases.
58        assertEquals(309, numberFormat.format(123).length());
59        assertEquals(309, numberFormat.format(BigInteger.valueOf(123)).length());
60    }
61
62    // Regression test for http://b/1897917: BigDecimal does not take into account multiplier.
63    public void testBigDecimalBug1897917() {
64        // For example. the BigDecimal 0.17 formatted in PercentInstance is 0% instead of 17%:
65        NumberFormat pf = NumberFormat.getPercentInstance();
66        assertEquals("17%", pf.format(BigDecimal.valueOf(0.17)));
67
68        // Test long decimal formatted in PercentInstance with various fractions.
69        String longDec = "11.2345678901234567890123456789012345678901234567890";
70        BigDecimal bd = new BigDecimal(longDec);
71        assertBigDecimalWithFraction(bd, "1,123.46%", 2);
72        assertBigDecimalWithFraction(bd, "1,123.45678901%", 8);
73        assertBigDecimalWithFraction(bd, "1,123.4567890123%", 10);
74        assertBigDecimalWithFraction(bd, "1,123.45678901234567890123%", 20);
75        assertBigDecimalWithFraction(bd, "1,123.456789012345678901234567890123%", 30);
76
77        // Test trailing zeros.
78        assertDecFmtWithMultiplierAndFraction("3333.33333333", 3, 4, "10,000");
79        assertDecFmtWithMultiplierAndFraction("3333.33333333", -3, 4, "-10,000");
80        assertDecFmtWithMultiplierAndFraction("0.00333333", 3, 4, "0.01");
81
82        assertDecFmtWithMultiplierAndFractionByLocale("3330000000000000000000000000000000", 3, 4,
83                    Locale.US, "9,990,000,000,000,000,000,000,000,000,000,000");
84
85        Locale en_IN = new Locale("en", "IN");
86        assertDecFmtWithMultiplierAndFractionByLocale("3330000000000000000000000000000000", 3, 4,
87                en_IN, "9,99,00,00,00,00,00,00,00,00,00,00,00,00,00,00,000");
88    }
89
90    public void testBigDecimalTestBigIntWithMultiplier() {
91        // Big integer tests.
92        assertDecFmtWithMultiplierAndFractionByLocale("123456789012345", 10, 0,
93                Locale.US, "1,234,567,890,123,450");
94        assertDecFmtWithMultiplierAndFractionByLocale("12345678901234567890", 10, 0,
95                Locale.US, "123,456,789,012,345,678,900");
96        assertDecFmtWithMultiplierAndFractionByLocale("98765432109876543210987654321", 10, 0,
97                Locale.US, "987,654,321,098,765,432,109,876,543,210");
98
99        assertDecFmtWithMultiplierAndFractionByLocale("123456789012345", -10, 0,
100                Locale.US, "-1,234,567,890,123,450");
101        assertDecFmtWithMultiplierAndFractionByLocale("12345678901234567890", -10, 0,
102                Locale.US, "-123,456,789,012,345,678,900");
103        assertDecFmtWithMultiplierAndFractionByLocale("98765432109876543210987654321", -10, 0,
104                Locale.US, "-987,654,321,098,765,432,109,876,543,210");
105
106        Locale en_IN = new Locale("en", "IN");
107        assertDecFmtWithMultiplierAndFractionByLocale("123456789012345", 10, 0,
108                en_IN, "1,23,45,67,89,01,23,450");
109        assertDecFmtWithMultiplierAndFractionByLocale("12345678901234567890", 10, 0,
110                en_IN, "12,34,56,78,90,12,34,56,78,900");
111        assertDecFmtWithMultiplierAndFractionByLocale("98765432109876543210987654321", 10, 0,
112                en_IN, "9,87,65,43,21,09,87,65,43,21,09,87,65,43,210");
113
114        assertDecFmtWithMultiplierAndFractionByLocale("123456789012345", -10, 0,
115                en_IN, "-1,23,45,67,89,01,23,450");
116        assertDecFmtWithMultiplierAndFractionByLocale("12345678901234567890", -10, 0,
117                en_IN, "-12,34,56,78,90,12,34,56,78,900");
118        assertDecFmtWithMultiplierAndFractionByLocale("98765432109876543210987654321", -10, 0,
119                en_IN, "-9,87,65,43,21,09,87,65,43,21,09,87,65,43,210");
120    }
121
122    public void testBigDecimalICUConsistency() {
123        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
124        df.setMaximumFractionDigits(2);
125        df.setMultiplier(2);
126        assertEquals(df.format(BigDecimal.valueOf(0.16)),
127                df.format(BigDecimal.valueOf(0.16).doubleValue()));
128        assertEquals(df.format(BigDecimal.valueOf(0.0293)),
129                df.format(BigDecimal.valueOf(0.0293).doubleValue()));
130        assertEquals(df.format(BigDecimal.valueOf(0.006)),
131                df.format(BigDecimal.valueOf(0.006).doubleValue()));
132        assertEquals(df.format(BigDecimal.valueOf(0.00283)),
133                df.format(BigDecimal.valueOf(0.00283).doubleValue()));
134        assertEquals(df.format(BigDecimal.valueOf(1.60)),
135        df.format(BigDecimal.valueOf(1.60).doubleValue()));
136        assertEquals(df.format(BigDecimal.valueOf(15)),
137                df.format(BigDecimal.valueOf(15).doubleValue()));
138        assertEquals(df.format(BigDecimal.valueOf(170)),
139                df.format(BigDecimal.valueOf(170).doubleValue()));
140        assertEquals(df.format(BigDecimal.valueOf(234.56)),
141                df.format(BigDecimal.valueOf(234.56).doubleValue()));
142        assertEquals(df.format(BigDecimal.valueOf(0)),
143        df.format(BigDecimal.valueOf(0).doubleValue()));
144        assertEquals(df.format(BigDecimal.valueOf(-1)),
145        df.format(BigDecimal.valueOf(-1).doubleValue()));
146        assertEquals(df.format(BigDecimal.valueOf(-10000)),
147        df.format(BigDecimal.valueOf(-10000).doubleValue()));
148        assertEquals(df.format(BigDecimal.valueOf(-0.001)),
149                df.format(BigDecimal.valueOf(-0.001).doubleValue()));
150        assertEquals(df.format(BigDecimal.valueOf(1234567890.1234567)),
151                df.format(BigDecimal.valueOf(1234567890.1234567).doubleValue()));
152        assertEquals(df.format(BigDecimal.valueOf(1.234567E100)),
153                df.format(BigDecimal.valueOf(1.234567E100).doubleValue()));
154    }
155
156    private void assertBigDecimalWithFraction(BigDecimal bd, String expectedResult, int fraction) {
157        NumberFormat pf = NumberFormat.getPercentInstance();
158        pf.setMaximumFractionDigits(fraction);
159        assertEquals(expectedResult, pf.format(bd));
160    }
161
162    private void assertDecFmtWithMultiplierAndFraction(String value, int multiplier, int fraction, String expectedResult) {
163        DecimalFormat df = (DecimalFormat)NumberFormat.getInstance();
164        df.setMultiplier(multiplier);
165        df.setMaximumFractionDigits(fraction);
166        BigDecimal d = new BigDecimal(value);
167        assertEquals(expectedResult, df.format(d));
168    }
169
170    private void assertDecFmtWithMultiplierAndFractionByLocale(String value, int multiplier, int fraction, Locale locale, String expectedResult) {
171        DecimalFormat df = (DecimalFormat)NumberFormat.getIntegerInstance(locale);
172        df.setMultiplier(multiplier);
173        df.setMaximumFractionDigits(fraction);
174        BigDecimal d = new BigDecimal(value);
175        assertEquals(expectedResult, df.format(d));
176    }
177
178    public void testSetZeroDigitForPattern() {
179        DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();
180        decimalFormatSymbols.setZeroDigit('a');
181        DecimalFormat formatter = new DecimalFormat();
182        formatter.setDecimalFormatSymbols(decimalFormatSymbols);
183        formatter.applyLocalizedPattern("#.aa");
184        assertEquals("e.fa", formatter.format(4.50));
185    }
186
187    public void testSetZeroDigitForFormatting() {
188        DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();
189        decimalFormatSymbols.setZeroDigit('a');
190        DecimalFormat formatter = new DecimalFormat();
191        formatter.setDecimalFormatSymbols(decimalFormatSymbols);
192        formatter.applyLocalizedPattern("#");
193        assertEquals("eadacab", formatter.format(4030201));
194    }
195
196    public void testBug9087737() throws Exception {
197        DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US);
198        // These shouldn't make valgrind unhappy.
199        df.setCurrency(Currency.getInstance("CHF"));
200        df.setCurrency(Currency.getInstance("GBP"));
201    }
202
203    // Check we don't crash on null inputs.
204    public void testBug15081434() throws Exception {
205      DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US);
206      try {
207        df.parse(null);
208        fail();
209      } catch (NullPointerException expected) {
210      }
211
212      try {
213        df.applyLocalizedPattern(null);
214        fail();
215      } catch (NullPointerException expected) {
216      }
217
218      try {
219        df.applyPattern(null);
220        fail();
221      } catch (NullPointerException expected) {
222      }
223
224      try {
225        df.applyPattern(null);
226        fail();
227      } catch (NullPointerException expected) {
228      }
229
230      try {
231        df.format(null, new StringBuffer(), new FieldPosition(0));
232        fail();
233      } catch (IllegalArgumentException expected) {
234      }
235
236      try {
237        df.parse(null, new ParsePosition(0));
238        fail();
239      } catch (NullPointerException expected) {
240      }
241
242      // This just ignores null.
243      df.setDecimalFormatSymbols(null);
244
245      try {
246        df.setCurrency(null);
247        fail();
248      } catch (NullPointerException expected) {
249      }
250
251      // These just ignore null.
252      df.setNegativePrefix(null);
253      df.setNegativeSuffix(null);
254      df.setPositivePrefix(null);
255      df.setPositiveSuffix(null);
256
257      try {
258        df.setRoundingMode(null);
259        fail();
260      } catch (NullPointerException expected) {
261      }
262    }
263
264    // Confirm the fraction digits do not change when the currency is changed.
265    public void testBug71369() {
266        final String nonBreakingSpace = "\u00A0";
267
268        NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.GERMAN);
269        numberFormat.setCurrency(Currency.getInstance("USD"));
270
271        assertEquals("2,01" + nonBreakingSpace + "$", numberFormat.format(2.01));
272
273        numberFormat.setMinimumFractionDigits(0);
274        numberFormat.setMaximumFractionDigits(0);
275
276        String expected = "2" + nonBreakingSpace + "$";
277        assertEquals(expected, numberFormat.format(2.01));
278
279        // Changing the currency must not reset the digits.
280        numberFormat.setCurrency(Currency.getInstance("EUR"));
281        numberFormat.setCurrency(Currency.getInstance("USD"));
282
283        assertEquals(expected, numberFormat.format(2.01));
284    }
285
286    // Confirm the currency symbol used by a format is determined by the locale of the format
287    // not the current default Locale.
288    public void testSetCurrency_symbolOrigin() {
289        Currency currency = Currency.getInstance("CNY");
290        Locale locale1 = Locale.CHINA;
291        Locale locale2 = Locale.US;
292        String locale1Symbol = currency.getSymbol(locale1);
293        String locale2Symbol = currency.getSymbol(locale2);
294        // This test only works if we can tell where the symbol came from, which requires they are
295        // different across the two locales chosen.
296        assertFalse(locale1Symbol.equals(locale2Symbol));
297
298        Locale originalLocale = Locale.getDefault();
299        try {
300            Locale.setDefault(locale1);
301            String amountDefaultLocale1 =
302                    formatArbitraryCurrencyAmountInLocale(currency, locale2);
303
304            Locale.setDefault(locale2);
305            String amountDefaultLocale2 =
306                    formatArbitraryCurrencyAmountInLocale(currency, locale2);
307
308            // This used to fail because Currency.getSymbol() was used without providing the
309            // format's locale.
310            assertEquals(amountDefaultLocale1, amountDefaultLocale2);
311        } finally {
312            Locale.setDefault(originalLocale);
313        }
314    }
315
316    private String formatArbitraryCurrencyAmountInLocale(Currency currency, Locale locale) {
317        NumberFormat localeCurrencyFormat = NumberFormat.getCurrencyInstance(locale);
318        localeCurrencyFormat.setCurrency(currency);
319        return localeCurrencyFormat.format(1000);
320    }
321}
322