1/*
2 *******************************************************************************
3 * Copyright (C) 2001-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 */
7
8/**
9 * Port From:   ICU4C v1.8.1 : format : NumberFormatTest
10 * Source File: $ICU4CRoot/source/test/intltest/numfmtst.cpp
11 **/
12
13package com.ibm.icu.dev.test.format;
14
15import java.io.IOException;
16import java.math.BigInteger;
17import java.text.AttributedCharacterIterator;
18import java.text.FieldPosition;
19import java.text.ParseException;
20import java.text.ParsePosition;
21import java.util.ArrayList;
22import java.util.Locale;
23import java.util.Set;
24
25import com.ibm.icu.dev.test.TestUtil;
26import com.ibm.icu.impl.ICUConfig;
27import com.ibm.icu.impl.LocaleUtility;
28import com.ibm.icu.impl.data.ResourceReader;
29import com.ibm.icu.impl.data.TokenIterator;
30import com.ibm.icu.math.BigDecimal;
31import com.ibm.icu.math.MathContext;
32import com.ibm.icu.text.DecimalFormat;
33import com.ibm.icu.text.DecimalFormatSymbols;
34import com.ibm.icu.text.DisplayContext;
35import com.ibm.icu.text.MeasureFormat;
36import com.ibm.icu.text.NumberFormat;
37import com.ibm.icu.text.NumberFormat.NumberFormatFactory;
38import com.ibm.icu.text.NumberFormat.SimpleNumberFormatFactory;
39import com.ibm.icu.util.Currency;
40import com.ibm.icu.util.CurrencyAmount;
41import com.ibm.icu.util.ULocale;
42
43public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
44
45    public static void main(String[] args) throws Exception {
46        new NumberFormatTest().run(args);
47    }
48
49    public void TestRoundingScientific10542() {
50        DecimalFormat format =
51                new DecimalFormat("0.00E0");
52
53        int[] roundingModes = {
54              BigDecimal.ROUND_CEILING,
55              BigDecimal.ROUND_DOWN,
56              BigDecimal.ROUND_FLOOR,
57              BigDecimal.ROUND_HALF_DOWN,
58              BigDecimal.ROUND_HALF_EVEN,
59              BigDecimal.ROUND_HALF_UP,
60              BigDecimal.ROUND_UP};
61        String[] descriptions = {
62                "Round Ceiling",
63                "Round Down",
64                "Round Floor",
65                "Round half down",
66                "Round half even",
67                "Round half up",
68                "Round up"};
69
70        double[] values = {-0.003006, -0.003005, -0.003004, 0.003014, 0.003015, 0.003016};
71        // The order of these expected values correspond to the order of roundingModes and the order of values.
72        String[][] expected = {
73                {"-3.00E-3", "-3.00E-3", "-3.00E-3", "3.02E-3", "3.02E-3", "3.02E-3"},
74                {"-3.00E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.01E-3"},
75                {"-3.01E-3", "-3.01E-3", "-3.01E-3", "3.01E-3", "3.01E-3", "3.01E-3"},
76                {"-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.02E-3"},
77                {"-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3"},
78                {"-3.01E-3", "-3.01E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3"},
79                {"-3.01E-3", "-3.01E-3", "-3.01E-3", "3.02E-3", "3.02E-3", "3.02E-3"}};
80        verifyRounding(format, values, expected, roundingModes, descriptions);
81        values = new double[]{-3006.0, -3005, -3004, 3014, 3015, 3016};
82        // The order of these expected values correspond to the order of roundingModes and the order of values.
83        expected = new String[][]{
84                {"-3.00E3", "-3.00E3", "-3.00E3", "3.02E3", "3.02E3", "3.02E3"},
85                {"-3.00E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.01E3"},
86                {"-3.01E3", "-3.01E3", "-3.01E3", "3.01E3", "3.01E3", "3.01E3"},
87                {"-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.02E3"},
88                {"-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3"},
89                {"-3.01E3", "-3.01E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3"},
90                {"-3.01E3", "-3.01E3", "-3.01E3", "3.02E3", "3.02E3", "3.02E3"}};
91        verifyRounding(format, values, expected, roundingModes, descriptions);
92        values = new double[]{0.0, -0.0};
93        // The order of these expected values correspond to the order of roundingModes and the order of values.
94        expected = new String[][]{
95                {"0.00E0", "-0.00E0"},
96                {"0.00E0", "-0.00E0"},
97                {"0.00E0", "-0.00E0"},
98                {"0.00E0", "-0.00E0"},
99                {"0.00E0", "-0.00E0"},
100                {"0.00E0", "-0.00E0"},
101                {"0.00E0", "-0.00E0"}};
102        verifyRounding(format, values, expected, roundingModes, descriptions);
103        values = new double[]{1e25, 1e25 + 1e15, 1e25 - 1e15};
104        // The order of these expected values correspond to the order of roundingModes and the order of values.
105        expected = new String[][]{
106                {"1.00E25", "1.01E25", "1.00E25"},
107                {"1.00E25", "1.00E25", "9.99E24"},
108                {"1.00E25", "1.00E25", "9.99E24"},
109                {"1.00E25", "1.00E25", "1.00E25"},
110                {"1.00E25", "1.00E25", "1.00E25"},
111                {"1.00E25", "1.00E25", "1.00E25"},
112                {"1.00E25", "1.01E25", "1.00E25"}};
113        verifyRounding(format, values, expected, roundingModes, descriptions);
114        values = new double[]{-1e25, -1e25 + 1e15, -1e25 - 1e15};
115        // The order of these expected values correspond to the order of roundingModes and the order of values.
116        expected = new String[][]{
117                {"-1.00E25", "-9.99E24", "-1.00E25"},
118                {"-1.00E25", "-9.99E24", "-1.00E25"},
119                {"-1.00E25", "-1.00E25", "-1.01E25"},
120                {"-1.00E25", "-1.00E25", "-1.00E25"},
121                {"-1.00E25", "-1.00E25", "-1.00E25"},
122                {"-1.00E25", "-1.00E25", "-1.00E25"},
123                {"-1.00E25", "-1.00E25", "-1.01E25"}};
124        verifyRounding(format, values, expected, roundingModes, descriptions);
125        values = new double[]{1e-25, 1e-25 + 1e-35, 1e-25 - 1e-35};
126        // The order of these expected values correspond to the order of roundingModes and the order of values.
127        expected = new String[][]{
128                {"1.00E-25", "1.01E-25", "1.00E-25"},
129                {"1.00E-25", "1.00E-25", "9.99E-26"},
130                {"1.00E-25", "1.00E-25", "9.99E-26"},
131                {"1.00E-25", "1.00E-25", "1.00E-25"},
132                {"1.00E-25", "1.00E-25", "1.00E-25"},
133                {"1.00E-25", "1.00E-25", "1.00E-25"},
134                {"1.00E-25", "1.01E-25", "1.00E-25"}};
135        verifyRounding(format, values, expected, roundingModes, descriptions);
136        values = new double[]{-1e-25, -1e-25 + 1e-35, -1e-25 - 1e-35};
137        // The order of these expected values correspond to the order of roundingModes and the order of values.
138        expected = new String[][]{
139                {"-1.00E-25", "-9.99E-26", "-1.00E-25"},
140                {"-1.00E-25", "-9.99E-26", "-1.00E-25"},
141                {"-1.00E-25", "-1.00E-25", "-1.01E-25"},
142                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
143                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
144                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
145                {"-1.00E-25", "-1.00E-25", "-1.01E-25"}};
146        verifyRounding(format, values, expected, roundingModes, descriptions);
147    }
148
149    private void verifyRounding(DecimalFormat format, double[] values, String[][] expected, int[] roundingModes,
150            String[] descriptions) {
151        for (int i = 0; i < roundingModes.length; i++) {
152            format.setRoundingMode(roundingModes[i]);
153            for (int j = 0; j < values.length; j++) {
154                assertEquals(descriptions[i]+" " +values[j], expected[i][j], format.format(values[j]));
155            }
156        }
157    }
158
159    public void Test10419RoundingWith0FractionDigits() {
160        Object[][] data = new Object[][]{
161                {BigDecimal.ROUND_CEILING, 1.488, "2"},
162                {BigDecimal.ROUND_DOWN, 1.588, "1"},
163                {BigDecimal.ROUND_FLOOR, 1.588, "1"},
164                {BigDecimal.ROUND_HALF_DOWN, 1.5, "1"},
165                {BigDecimal.ROUND_HALF_EVEN, 2.5, "2"},
166                {BigDecimal.ROUND_HALF_UP, 2.5, "3"},
167                {BigDecimal.ROUND_UP, 1.5, "2"},
168        };
169        NumberFormat nff = NumberFormat.getNumberInstance(ULocale.ENGLISH);
170        nff.setMaximumFractionDigits(0);
171        for (Object[] item : data) {
172          nff.setRoundingMode(((Integer) item[0]).intValue());
173          assertEquals("Test10419", item[2], nff.format(item[1]));
174        }
175    }
176
177    public void TestParseNegativeWithFaLocale() {
178        DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("fa"));
179        try {
180            double value = parser.parse("-0,5").doubleValue();
181            assertEquals("Expect -0.5", -0.5, value);
182        } catch (ParseException e) {
183            this.errln("Parsing -0.5 should have succeeded.");
184        }
185    }
186
187    public void TestParseNegativeWithAlternativeMinusSign() {
188        DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("en"));
189        try {
190            double value = parser.parse("\u208B0.5").doubleValue();
191            assertEquals("Expect -0.5", -0.5, value);
192        } catch (ParseException e) {
193            this.errln("Parsing -0.5 should have succeeded.");
194        }
195    }
196
197    // Test various patterns
198    public void TestPatterns() {
199
200        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
201        final String pat[]    = { "#.#", "#.", ".#", "#" };
202        int pat_length = pat.length;
203        final String newpat[] = { "#0.#", "#0.", "#.0", "#" };
204        final String num[]    = { "0",   "0.", ".0", "0" };
205        for (int i=0; i<pat_length; ++i)
206        {
207            DecimalFormat fmt = new DecimalFormat(pat[i], sym);
208            String newp = fmt.toPattern();
209            if (!newp.equals(newpat[i]))
210                errln("FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
211                        "; " + newp + " seen instead");
212
213            String s = ((NumberFormat)fmt).format(0);
214            if (!s.equals(num[i]))
215            {
216                errln("FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
217                        "; " + s + " seen instead");
218                logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
219            }
220            // BigInteger 0 - ticket#4731
221            s = ((NumberFormat)fmt).format(BigInteger.ZERO);
222            if (!s.equals(num[i]))
223            {
224                errln("FAIL: Pattern " + pat[i] + " should format BigInteger zero as " + num[i] +
225                        "; " + s + " seen instead");
226                logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
227            }
228        }
229    }
230
231    // Test exponential pattern
232    public void TestExponential() {
233
234        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
235        final String pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
236        int pat_length = pat.length;
237
238        double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
239        int val_length = val.length;
240        final String valFormat[] = {
241                // 0.####E0
242                "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
243                // 00.000E00
244                "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
245                // ##0.######E000
246                "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
247                // 0.###E0;[0.###E0]
248                "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" };
249        /*double valParse[] =
250            {
251                0.01234, 123460000, 1.23E300, -3.1416E-271,
252                0.01234, 123460000, 1.23E300, -3.1416E-271,
253                0.01234, 123456800, 1.23E300, -3.141593E-271,
254                0.01234, 123500000, 1.23E300, -3.142E-271,
255            };*/ //The variable is never used
256
257        int lval[] = { 0, -1, 1, 123456789 };
258        int lval_length = lval.length;
259        final String lvalFormat[] = {
260                // 0.####E0
261                "0E0", "-1E0", "1E0", "1.2346E8",
262                // 00.000E00
263                "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
264                // ##0.######E000
265                "0E000", "-1E000", "1E000", "123.4568E006",
266                // 0.###E0;[0.###E0]
267                "0E0", "[1E0]", "1E0", "1.235E8" };
268        int lvalParse[] =
269            {
270                0, -1, 1, 123460000,
271                0, -1, 1, 123460000,
272                0, -1, 1, 123456800,
273                0, -1, 1, 123500000,
274            };
275        int ival = 0, ilval = 0;
276        for (int p = 0; p < pat_length; ++p) {
277            DecimalFormat fmt = new DecimalFormat(pat[p], sym);
278            logln("Pattern \"" + pat[p] + "\" -toPattern-> \"" + fmt.toPattern() + "\"");
279            int v;
280            for (v = 0; v < val_length; ++v) {
281                String s;
282                s = ((NumberFormat) fmt).format(val[v]);
283                logln(" " + val[v] + " -format-> " + s);
284                if (!s.equals(valFormat[v + ival]))
285                    errln("FAIL: Expected " + valFormat[v + ival]);
286
287                ParsePosition pos = new ParsePosition(0);
288                double a = fmt.parse(s, pos).doubleValue();
289                if (pos.getIndex() == s.length()) {
290                    logln("  -parse-> " + Double.toString(a));
291                    // Use epsilon comparison as necessary
292                } else
293                    errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
294            }
295            for (v = 0; v < lval_length; ++v) {
296                String s;
297                s = ((NumberFormat) fmt).format(lval[v]);
298                logln(" " + lval[v] + "L -format-> " + s);
299                if (!s.equals(lvalFormat[v + ilval]))
300                    errln("ERROR: Expected " + lvalFormat[v + ilval] + " Got: " + s);
301
302                ParsePosition pos = new ParsePosition(0);
303                long a = 0;
304                Number A = fmt.parse(s, pos);
305                if (A != null) {
306                    a = A.longValue();
307                    if (pos.getIndex() == s.length()) {
308                        logln("  -parse-> " + a);
309                        if (a != lvalParse[v + ilval])
310                            errln("FAIL: Expected " + lvalParse[v + ilval]);
311                    } else
312                        errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + Long.toString(a));
313                } else {
314                    errln("Fail to parse the string: " + s);
315                }
316            }
317            ival += val_length;
318            ilval += lval_length;
319        }
320    }
321
322    // Test the handling of quotes
323    public void TestQuotes() {
324
325        StringBuffer pat;
326        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
327        pat = new StringBuffer("a'fo''o'b#");
328        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
329        String s = ((NumberFormat)fmt).format(123);
330        logln("Pattern \"" + pat + "\"");
331        logln(" Format 123 . " + s);
332        if (!s.equals("afo'ob123"))
333            errln("FAIL: Expected afo'ob123");
334
335        s ="";
336        pat = new StringBuffer("a''b#");
337        fmt = new DecimalFormat(pat.toString(), sym);
338        s = ((NumberFormat)fmt).format(123);
339        logln("Pattern \"" + pat + "\"");
340        logln(" Format 123 . " + s);
341        if (!s.equals("a'b123"))
342            errln("FAIL: Expected a'b123");
343    }
344
345    public void TestParseCurrencyTrailingSymbol() {
346        // see sun bug 4709840
347        NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.GERMANY);
348        float val = 12345.67f;
349        String str = fmt.format(val);
350        logln("val: " + val + " str: " + str);
351        try {
352            Number num = fmt.parse(str);
353            logln("num: " + num);
354        } catch (ParseException e) {
355            errln("parse of '" + str + "' threw exception: " + e);
356        }
357    }
358
359    /**
360     * Test the handling of the currency symbol in patterns.
361     **/
362    public void TestCurrencySign() {
363        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
364        StringBuffer pat = new StringBuffer("");
365        char currency = 0x00A4;
366        // "\xA4#,##0.00;-\xA4#,##0.00"
367        pat.append(currency).append("#,##0.00;-").append(currency).append("#,##0.00");
368        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
369        String s = ((NumberFormat) fmt).format(1234.56);
370        pat = new StringBuffer();
371        logln("Pattern \"" + fmt.toPattern() + "\"");
372        logln(" Format " + 1234.56 + " . " + s);
373        assertEquals("symbol, pos", "$1,234.56", s);
374
375        s = ((NumberFormat) fmt).format(-1234.56);
376        logln(" Format " + Double.toString(-1234.56) + " . " + s);
377        assertEquals("symbol, neg", "-$1,234.56", s);
378
379        pat.setLength(0);
380        // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
381        pat.append(currency).append(currency).append(" #,##0.00;").append(currency).append(currency).append(" -#,##0.00");
382        fmt = new DecimalFormat(pat.toString(), sym);
383        s = ((NumberFormat) fmt).format(1234.56);
384        logln("Pattern \"" + fmt.toPattern() + "\"");
385        logln(" Format " + Double.toString(1234.56) + " . " + s);
386        assertEquals("name, pos", "USD 1,234.56", s);
387
388        s = ((NumberFormat) fmt).format(-1234.56);
389        logln(" Format " + Double.toString(-1234.56) + " . " + s);
390        assertEquals("name, neg", "USD -1,234.56", s);
391    }
392
393    public void TestSpaceParsing() {
394        // the data are:
395        // the string to be parsed, parsed position, parsed error index
396        String[][] DATA = {
397                {"$124", "4", "-1"},
398                {"$124 $124", "4", "-1"},
399                {"$124 ", "4", "-1"},
400                {"$ 124 ", "5", "-1"},
401                {"$\u00A0124 ", "5", "-1"},
402                {" $ 124 ", "0", "0"}, // TODO: need to handle space correctly
403                {"124$", "0", "3"}, // TODO: need to handle space correctly
404                // {"124 $", "5", "-1"}, TODO: OK or NOT?
405                {"124 $", "0", "3"},
406        };
407        NumberFormat foo = NumberFormat.getCurrencyInstance();
408        for (int i = 0; i < DATA.length; ++i) {
409            ParsePosition parsePosition = new ParsePosition(0);
410            String stringToBeParsed = DATA[i][0];
411            int parsedPosition = Integer.parseInt(DATA[i][1]);
412            int errorIndex = Integer.parseInt(DATA[i][2]);
413            try {
414                Number result = foo.parse(stringToBeParsed, parsePosition);
415                if (parsePosition.getIndex() != parsedPosition ||
416                        parsePosition.getErrorIndex() != errorIndex) {
417                    errln("FAILED parse " + stringToBeParsed + "; parse position: " + parsePosition.getIndex() + "; error position: " + parsePosition.getErrorIndex());
418                }
419                if (parsePosition.getErrorIndex() == -1 &&
420                        result.doubleValue() != 124) {
421                    errln("FAILED parse " + stringToBeParsed + "; value " + result.doubleValue());
422                }
423            } catch (Exception e) {
424                errln("FAILED " + e.toString());
425            }
426        }
427    }
428
429
430    public void TestMultiCurrencySign() {
431        String[][] DATA = {
432                // the fields in the following test are:
433                // locale,
434                // currency pattern (with negative pattern),
435                // currency number to be formatted,
436                // currency format using currency symbol name, such as "$" for USD,
437                // currency format using currency ISO name, such as "USD",
438                // currency format using plural name, such as "US dollars".
439                // for US locale
440                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1234.56", "$1,234.56", "USD1,234.56", "US dollars1,234.56"},
441                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD1,234.56", "-US dollars1,234.56"},
442                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollars1.00"},
443                // for CHINA locale
444                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1234.56", "\uFFE51,234.56", "CNY1,234.56", "\u4EBA\u6C11\u5E011,234.56"},
445                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "-1234.56", "(\uFFE51,234.56)", "(CNY1,234.56)", "(\u4EBA\u6C11\u5E011,234.56)"},
446                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1", "\uFFE51.00", "CNY1.00", "\u4EBA\u6C11\u5E011.00"}
447        };
448
449        String doubleCurrencyStr = "\u00A4\u00A4";
450        String tripleCurrencyStr = "\u00A4\u00A4\u00A4";
451
452        for (int i=0; i<DATA.length; ++i) {
453            String locale = DATA[i][0];
454            String pat = DATA[i][1];
455            Double numberToBeFormat = new Double(DATA[i][2]);
456            DecimalFormatSymbols sym = new DecimalFormatSymbols(new ULocale(locale));
457            for (int j=1; j<=3; ++j) {
458                // j represents the number of currency sign in the pattern.
459                if (j == 2) {
460                    pat = pat.replaceAll("\u00A4", doubleCurrencyStr);
461                } else if (j == 3) {
462                    pat = pat.replaceAll("\u00A4\u00A4", tripleCurrencyStr);
463                }
464                DecimalFormat fmt = new DecimalFormat(pat, sym);
465                String s = ((NumberFormat) fmt).format(numberToBeFormat);
466                // DATA[i][3] is the currency format result using a
467                // single currency sign.
468                // DATA[i][4] is the currency format result using
469                // double currency sign.
470                // DATA[i][5] is the currency format result using
471                // triple currency sign.
472                // DATA[i][j+2] is the currency format result using
473                // 'j' number of currency sign.
474                String currencyFormatResult = DATA[i][2+j];
475                if (!s.equals(currencyFormatResult)) {
476                    errln("FAIL format: Expected " + currencyFormatResult);
477                }
478                try {
479                    // mix style parsing
480                    for (int k=3; k<=5; ++k) {
481                        // DATA[i][3] is the currency format result using a
482                        // single currency sign.
483                        // DATA[i][4] is the currency format result using
484                        // double currency sign.
485                        // DATA[i][5] is the currency format result using
486                        // triple currency sign.
487                        String oneCurrencyFormat = DATA[i][k];
488                        if (fmt.parse(oneCurrencyFormat).doubleValue() !=
489                                numberToBeFormat.doubleValue()) {
490                            errln("FAILED parse " + oneCurrencyFormat);
491                        }
492                    }
493                } catch (ParseException e) {
494                    errln("FAILED, DecimalFormat parse currency: " + e.toString());
495                }
496            }
497        }
498    }
499
500    public void TestCurrencyFormatForMixParsing() {
501        MeasureFormat curFmt = MeasureFormat.getCurrencyFormat(new ULocale("en_US"));
502        String[] formats = {
503                "$1,234.56",  // string to be parsed
504                "USD1,234.56",
505                "US dollars1,234.56",
506                "1,234.56 US dollars"
507        };
508        try {
509            for (int i = 0; i < formats.length; ++i) {
510                String stringToBeParsed = formats[i];
511                CurrencyAmount parsedVal = (CurrencyAmount)curFmt.parseObject(stringToBeParsed);
512                Number val = parsedVal.getNumber();
513                if (!val.equals(new BigDecimal("1234.56"))) {
514                    errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number. val=" + val);
515                }
516                if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
517                    errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
518                }
519            }
520        } catch (ParseException e) {
521            errln("parse FAILED: " + e.toString());
522        }
523    }
524
525    public void TestDecimalFormatCurrencyParse() {
526        // Locale.US
527        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
528        StringBuffer pat = new StringBuffer("");
529        char currency = 0x00A4;
530        // "\xA4#,##0.00;-\xA4#,##0.00"
531        pat.append(currency).append(currency).append(currency).append("#,##0.00;-").append(currency).append(currency).append(currency).append("#,##0.00");
532        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
533        String[][] DATA = {
534                // the data are:
535                // string to be parsed, the parsed result (number)
536                {"$1.00", "1"},
537                {"USD1.00", "1"},
538                {"1.00 US dollar", "1"},
539                {"$1,234.56", "1234.56"},
540                {"USD1,234.56", "1234.56"},
541                {"1,234.56 US dollar", "1234.56"},
542        };
543        try {
544            for (int i = 0; i < DATA.length; ++i) {
545                String stringToBeParsed = DATA[i][0];
546                double parsedResult = Double.parseDouble(DATA[i][1]);
547                Number num = fmt.parse(stringToBeParsed);
548                if (num.doubleValue() != parsedResult) {
549                    errln("FAIL parse: Expected " + parsedResult);
550                }
551            }
552        } catch (ParseException e) {
553            errln("FAILED, DecimalFormat parse currency: " + e.toString());
554        }
555    }
556
557    /**
558     * Test localized currency patterns.
559     */
560    public void TestCurrency() {
561        String[] DATA = {
562                "fr", "CA", "", "1,50\u00a0$",
563                "de", "DE", "", "1,50\u00a0\u20AC",
564                "de", "DE", "PREEURO", "1,50\u00a0DM",
565                "fr", "FR", "", "1,50\u00a0\u20AC",
566                "fr", "FR", "PREEURO", "1,50\u00a0F",
567        };
568
569        for (int i=0; i<DATA.length; i+=4) {
570            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
571            NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
572            String s = fmt.format(1.50);
573            if (s.equals(DATA[i+3])) {
574                logln("Ok: 1.50 x " + locale + " => " + s);
575            } else {
576                logln("FAIL: 1.50 x " + locale + " => " + s +
577                        ", expected " + DATA[i+3]);
578            }
579        }
580
581        // format currency with CurrencyAmount
582        for (int i=0; i<DATA.length; i+=4) {
583            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
584
585            Currency curr = Currency.getInstance(locale);
586            logln("\nName of the currency is: " + curr.getName(locale, Currency.LONG_NAME, new boolean[] {false}));
587            CurrencyAmount cAmt = new CurrencyAmount(1.5, curr);
588            logln("CurrencyAmount object's hashCode is: " + cAmt.hashCode()); //cover hashCode
589
590            NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
591            String sCurr = fmt.format(cAmt);
592            if (sCurr.equals(DATA[i+3])) {
593                logln("Ok: 1.50 x " + locale + " => " + sCurr);
594            } else {
595                errln("FAIL: 1.50 x " + locale + " => " + sCurr +
596                        ", expected " + DATA[i+3]);
597            }
598        }
599
600        //Cover MeasureFormat.getCurrencyFormat()
601        ULocale save = ULocale.getDefault();
602        ULocale.setDefault(ULocale.US);
603        MeasureFormat curFmt = MeasureFormat.getCurrencyFormat();
604        String strBuf = curFmt.format(new CurrencyAmount(new Float(1234.56), Currency.getInstance("USD")));
605
606        try {
607            CurrencyAmount parsedVal = (CurrencyAmount)curFmt.parseObject(strBuf);
608            Number val = parsedVal.getNumber();
609            if (!val.equals(new BigDecimal("1234.56"))) {
610                errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number. val=" + val);
611            }
612            if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
613                errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
614            }
615        }
616        catch (ParseException e) {
617            errln("FAIL: " + e.getMessage());
618        }
619        ULocale.setDefault(save);
620    }
621
622    public void TestCurrencyIsoPluralFormat() {
623        String[][] DATA = {
624                // the data are:
625                // locale,
626                // currency amount to be formatted,
627                // currency ISO code to be formatted,
628                // format result using CURRENCYSTYLE,
629                // format result using ISOCURRENCYSTYLE,
630                // format result using PLURALCURRENCYSTYLE,
631                {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollars"},
632                {"en_US", "1234.56", "USD", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
633                {"en_US", "-1234.56", "USD", "-$1,234.56", "-USD1,234.56", "-1,234.56 US dollars"},
634                {"zh_CN", "1", "USD", "US$\u00A01.00", "USD\u00A01.00", "1.00美元"},
635                {"zh_CN", "1234.56", "USD", "US$\u00A01,234.56", "USD\u00A01,234.56", "1,234.56美元"},
636                {"zh_CN", "1", "CNY", "¥\u00A01.00", "CNY\u00A01.00", "1.00人民币"},
637                {"zh_CN", "1234.56", "CNY", "¥\u00A01,234.56", "CNY\u00A01,234.56", "1,234.56人民币"},
638                {"ru_RU", "1", "RUB", "1,00 руб.", "1,00 RUB", "1,00 российского рубля"},
639                {"ru_RU", "2", "RUB", "2,00 руб.", "2,00 RUB", "2,00 российского рубля"},
640                {"ru_RU", "5", "RUB", "5,00 руб.", "5,00 RUB", "5,00 российского рубля"},
641                // test locale without currency information
642                {"root", "-1.23", "USD", "-US$ 1.23", "-USD 1.23", "-1.23 USD"},
643                {"root@numbers=latn", "-1.23", "USD", "-US$ 1.23", "-USD 1.23", "-1.23 USD"}, // ensure that the root locale is still used with modifiers
644                {"root@numbers=arab", "-1.23", "USD", "\u200F-US$ ١٫٢٣", "\u200F-USD ١٫٢٣", "\u200F-١٫٢٣ USD"}, // ensure that the root locale is still used with modifiers
645                {"es_AR", "1", "INR", "INR1,00", "INR1,00", "1,00 rupia india"},
646                {"ar_EG", "1", "USD", "US$ ١٫٠٠", "USD ١٫٠٠", "١٫٠٠ دولار أمريكي"},
647        };
648
649        for (int i=0; i<DATA.length; ++i) {
650            for (int k = NumberFormat.CURRENCYSTYLE;
651                    k <= NumberFormat.PLURALCURRENCYSTYLE;
652                    ++k) {
653                // k represents currency format style.
654                if ( k != NumberFormat.CURRENCYSTYLE &&
655                        k != NumberFormat.ISOCURRENCYSTYLE &&
656                        k != NumberFormat.PLURALCURRENCYSTYLE ) {
657                    continue;
658                }
659                String localeString = DATA[i][0];
660                Double numberToBeFormat = new Double(DATA[i][1]);
661                String currencyISOCode = DATA[i][2];
662                ULocale locale = new ULocale(localeString);
663                NumberFormat numFmt = NumberFormat.getInstance(locale, k);
664                numFmt.setCurrency(Currency.getInstance(currencyISOCode));
665                String strBuf = numFmt.format(numberToBeFormat);
666                int resultDataIndex = k-1;
667                if ( k == NumberFormat.CURRENCYSTYLE ) {
668                    resultDataIndex = k+2;
669                }
670                // DATA[i][resultDataIndex] is the currency format result
671                // using 'k' currency style.
672                String formatResult = DATA[i][resultDataIndex];
673                if (!strBuf.equals(formatResult)) {
674                    errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
675                }
676                try {
677                    // test parsing, and test parsing for all currency formats.
678                    for (int j = 3; j < 6; ++j) {
679                        // DATA[i][3] is the currency format result using
680                        // CURRENCYSTYLE formatter.
681                        // DATA[i][4] is the currency format result using
682                        // ISOCURRENCYSTYLE formatter.
683                        // DATA[i][5] is the currency format result using
684                        // PLURALCURRENCYSTYLE formatter.
685                        String oneCurrencyFormatResult = DATA[i][j];
686                        Number val = numFmt.parse(oneCurrencyFormatResult);
687                        if (val.doubleValue() != numberToBeFormat.doubleValue()) {
688                            errln("FAIL: getCurrencyFormat of locale " + localeString + " failed roundtripping the number. val=" + val + "; expected: " + numberToBeFormat);
689                        }
690                    }
691                }
692                catch (ParseException e) {
693                    errln("FAIL: " + e.getMessage());
694                }
695            }
696        }
697    }
698
699
700    public void TestMiscCurrencyParsing() {
701        String[][] DATA = {
702                // each has: string to be parsed, parsed position, error position
703                {"1.00 ", "0", "4"},
704                {"1.00 UAE dirha", "0", "4"},
705                {"1.00 us dollar", "14", "-1"},
706                {"1.00 US DOLLAR", "14", "-1"},
707                {"1.00 usd", "0", "4"},
708        };
709        ULocale locale = new ULocale("en_US");
710        for (int i=0; i<DATA.length; ++i) {
711            String stringToBeParsed = DATA[i][0];
712            int parsedPosition = Integer.parseInt(DATA[i][1]);
713            int errorIndex = Integer.parseInt(DATA[i][2]);
714            NumberFormat numFmt = NumberFormat.getInstance(locale, NumberFormat.CURRENCYSTYLE);
715            ParsePosition parsePosition = new ParsePosition(0);
716            Number val = numFmt.parse(stringToBeParsed, parsePosition);
717            if (parsePosition.getIndex() != parsedPosition ||
718                    parsePosition.getErrorIndex() != errorIndex) {
719                errln("FAIL: parse failed. expected error position: " + errorIndex + "; actual: " + parsePosition.getErrorIndex());
720                errln("FAIL: parse failed. expected position: " + parsedPosition +"; actual: " + parsePosition.getIndex());
721            }
722            if (parsePosition.getErrorIndex() == -1 &&
723                    val.doubleValue() != 1.00) {
724                errln("FAIL: parse failed. expected 1.00, actual:" + val);
725            }
726        }
727    }
728
729    public void TestParseCurrency() {
730        class ParseCurrencyItem {
731            private final String localeString;
732            private final String descrip;
733            private final String currStr;
734            private final int    numExpectPos;
735            private final int    numExpectVal;
736            private final int    curExpectPos;
737            private final int    curExpectVal;
738            private final String curExpectCurr;
739
740            ParseCurrencyItem(String locStr, String desc, String curr, int numExPos, int numExVal, int curExPos, int curExVal, String curExCurr) {
741                localeString  = locStr;
742                descrip       = desc;
743                currStr       = curr;
744                numExpectPos  = numExPos;
745                numExpectVal  = numExVal;
746                curExpectPos  = curExPos;
747                curExpectVal  = curExVal;
748                curExpectCurr = curExCurr;
749            }
750            public String getLocaleString()  { return localeString; }
751            public String getDescrip()       { return descrip; }
752            public String getCurrStr()       { return currStr; }
753            public int    getNumExpectPos()  { return numExpectPos; }
754            public int    getNumExpectVal()  { return numExpectVal; }
755            public int    getCurExpectPos()  { return curExpectPos; }
756            public int    getCurExpectVal()  { return curExpectVal; }
757            public String getCurExpectCurr() { return curExpectCurr; }
758        }
759        final ParseCurrencyItem[] parseCurrencyItems = {
760                new ParseCurrencyItem( "en_US", "dollars2", "$2.00",            5,  2,  5,  2,  "USD" ),
761                new ParseCurrencyItem( "en_US", "dollars4", "$4",               2,  4,  2,  4,  "USD" ),
762                new ParseCurrencyItem( "en_US", "dollars9", "9\u00A0$",         0,  0,  0,  0,  ""    ),
763                new ParseCurrencyItem( "en_US", "pounds3",  "\u00A33.00",       0,  0,  5,  3,  "GBP" ),
764                new ParseCurrencyItem( "en_US", "pounds5",  "\u00A35",          0,  0,  2,  5,  "GBP" ),
765                new ParseCurrencyItem( "en_US", "pounds7",  "7\u00A0\u00A3",    0,  0,  0,  0,  ""    ),
766                new ParseCurrencyItem( "en_US", "euros8",   "\u20AC8",          0,  0,  2,  8,  "EUR" ),
767
768                new ParseCurrencyItem( "en_GB", "pounds3",  "\u00A33.00",       5,  3,  5,  3,  "GBP" ),
769                new ParseCurrencyItem( "en_GB", "pounds5",  "\u00A35",          2,  5,  2,  5,  "GBP" ),
770                new ParseCurrencyItem( "en_GB", "pounds7",  "7\u00A0\u00A3",    0,  0,  0,  0,  ""    ),
771                new ParseCurrencyItem( "en_GB", "euros4",   "4,00\u00A0\u20AC", 0,  0,  0,  0,  ""    ),
772                new ParseCurrencyItem( "en_GB", "euros6",   "6\u00A0\u20AC",    0,  0,  0,  0,  ""    ),
773                new ParseCurrencyItem( "en_GB", "euros8",   "\u20AC8",          0,  0,  2,  8,  "EUR" ),
774                new ParseCurrencyItem( "en_GB", "dollars4", "$4",               0,  0,  2,  4,  "USD" ),
775
776                new ParseCurrencyItem( "fr_FR", "euros4",   "4,00\u00A0\u20AC", 6,  4,  6,  4,  "EUR" ),
777                new ParseCurrencyItem( "fr_FR", "euros6",   "6\u00A0\u20AC",    3,  6,  3,  6,  "EUR" ),
778                new ParseCurrencyItem( "fr_FR", "euros8",   "\u20AC8",          0,  0,  0,  0,  ""    ),
779                new ParseCurrencyItem( "fr_FR", "dollars2", "$2.00",            0,  0,  0,  0,  ""    ),
780                new ParseCurrencyItem( "fr_FR", "dollars4", "$4",               0,  0,  0,  0,  ""    ),
781        };
782        for (ParseCurrencyItem item: parseCurrencyItems) {
783            String localeString = item.getLocaleString();
784            ULocale uloc = new ULocale(localeString);
785            NumberFormat fmt = null;
786            try {
787                fmt = NumberFormat.getCurrencyInstance(uloc);
788            } catch (Exception e) {
789                errln("NumberFormat.getCurrencyInstance fails for locale " + localeString);
790                continue;
791            }
792            String currStr = item.getCurrStr();
793            ParsePosition parsePos = new ParsePosition(0);
794
795            Number numVal = fmt.parse(currStr, parsePos);
796            if ( parsePos.getIndex() != item.getNumExpectPos() || (numVal != null && numVal.intValue() != item.getNumExpectVal()) ) {
797                if (numVal != null) {
798                    errln("NumberFormat.getCurrencyInstance parse " + localeString + "/" + item.getDescrip() +
799                            ", expect pos/val " + item.getNumExpectPos() + "/" + item.getNumExpectVal() +
800                            ", get " + parsePos.getIndex() + "/" + numVal.intValue() );
801                } else {
802                    errln("NumberFormat.getCurrencyInstance parse " + localeString + "/" + item.getDescrip() +
803                            ", expect pos/val " + item.getNumExpectPos() + "/" + item.getNumExpectVal() +
804                            ", get " + parsePos.getIndex() + "/(NULL)" );
805                }
806            }
807
808            parsePos.setIndex(0);
809            CurrencyAmount currAmt = fmt.parseCurrency(currStr, parsePos);
810            if ( parsePos.getIndex() != item.getCurExpectPos() || (currAmt != null && (currAmt.getNumber().intValue() != item.getCurExpectVal() ||
811                    currAmt.getCurrency().getCurrencyCode().compareTo(item.getCurExpectCurr()) != 0)) ) {
812                if (currAmt != null) {
813                    errln("NumberFormat.getCurrencyInstance parseCurrency " + localeString + "/" + item.getDescrip() +
814                            ", expect pos/val/curr " + item.getCurExpectPos() + "/" + item.getCurExpectVal() + "/" + item.getCurExpectCurr() +
815                            ", get " + parsePos.getIndex() + "/" + currAmt.getNumber().intValue() + "/" + currAmt.getCurrency().getCurrencyCode() );
816                } else {
817                    errln("NumberFormat.getCurrencyInstance parseCurrency " + localeString + "/" + item.getDescrip() +
818                            ", expect pos/val/curr " + item.getCurExpectPos() + "/" + item.getCurExpectVal() + "/" + item.getCurExpectCurr() +
819                            ", get " + parsePos.getIndex() + "/(NULL)" );
820                }
821            }
822        }
823    }
824
825    /**
826     * Test the Currency object handling, new as of ICU 2.2.
827     */
828    public void TestCurrencyObject() {
829        NumberFormat fmt =
830                NumberFormat.getCurrencyInstance(Locale.US);
831
832        expectCurrency(fmt, null, 1234.56, "$1,234.56");
833
834        expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
835                1234.56, "\u20AC1,234.56"); // Euro
836
837        expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
838                1234.56, "\u00A51,235"); // Yen
839
840        expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
841                1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
842
843        expectCurrency(fmt, Currency.getInstance(Locale.US),
844                1234.56, "$1,234.56");
845
846        fmt = NumberFormat.getCurrencyInstance(Locale.FRANCE);
847
848        expectCurrency(fmt, null, 1234.56, "1 234,56 \u20AC");
849
850        expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
851                1234.56, "1 235 JPY"); // Yen
852
853        expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
854                1234.56, "1 234,56 CHF"); // no more rounding here, see cldrbug 5548
855
856        expectCurrency(fmt, Currency.getInstance(Locale.US),
857                1234.56, "1 234,56 $US");
858
859        expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
860                1234.56, "1 234,56 \u20AC"); // Euro
861    }
862
863    public void TestCompatibleCurrencies() {
864        NumberFormat fmt =
865                NumberFormat.getCurrencyInstance(Locale.US);
866        expectParseCurrency(fmt, Currency.getInstance(Locale.JAPAN), "\u00A51,235"); // Yen half-width
867        expectParseCurrency(fmt, Currency.getInstance(Locale.JAPAN), "\uFFE51,235"); // Yen full-wdith
868    }
869
870    public void TestCurrencyPatterns() {
871        int i;
872        Locale[] locs = NumberFormat.getAvailableLocales();
873        for (i=0; i<locs.length; ++i) {
874            NumberFormat nf = NumberFormat.getCurrencyInstance(locs[i]);
875            // Make sure currency formats do not have a variable number
876            // of fraction digits
877            int min = nf.getMinimumFractionDigits();
878            int max = nf.getMaximumFractionDigits();
879            if (min != max) {
880                String a = nf.format(1.0);
881                String b = nf.format(1.125);
882                errln("FAIL: " + locs[i] +
883                        " min fraction digits != max fraction digits; "+
884                        "x 1.0 => " + a +
885                        "; x 1.125 => " + b);
886            }
887
888            // Make sure EURO currency formats have exactly 2 fraction digits
889            if (nf instanceof DecimalFormat) {
890                Currency curr = ((DecimalFormat) nf).getCurrency();
891                if (curr != null && "EUR".equals(curr.getCurrencyCode())) {
892                    if (min != 2 || max != 2) {
893                        String a = nf.format(1.0);
894                        errln("FAIL: " + locs[i] +
895                                " is a EURO format but it does not have 2 fraction digits; "+
896                                "x 1.0 => " +
897                                a);
898                    }
899                }
900            }
901        }
902    }
903
904    /**
905     * Do rudimentary testing of parsing.
906     */
907    public void TestParse() {
908        String arg = "0.0";
909        DecimalFormat format = new DecimalFormat("00");
910        double aNumber = 0l;
911        try {
912            aNumber = format.parse(arg).doubleValue();
913        } catch (ParseException e) {
914            System.out.println(e);
915        }
916        logln("parse(" + arg + ") = " + aNumber);
917    }
918
919    /**
920     * Test proper rounding by the format method.
921     */
922    public void TestRounding487() {
923
924        NumberFormat nf = NumberFormat.getInstance();
925        roundingTest(nf, 0.00159999, 4, "0.0016");
926        roundingTest(nf, 0.00995, 4, "0.01");
927
928        roundingTest(nf, 12.3995, 3, "12.4");
929
930        roundingTest(nf, 12.4999, 0, "12");
931        roundingTest(nf, - 19.5, 0, "-20");
932
933    }
934
935    /**
936     * Test the functioning of the secondary grouping value.
937     */
938    public void TestSecondaryGrouping() {
939
940        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
941        DecimalFormat f = new DecimalFormat("#,##,###", US);
942
943        expect(f, 123456789L, "12,34,56,789");
944        expectPat(f, "#,##,###");
945        f.applyPattern("#,###");
946
947        f.setSecondaryGroupingSize(4);
948        expect(f, 123456789L, "12,3456,789");
949        expectPat(f, "#,####,###");
950        NumberFormat g = NumberFormat.getInstance(new Locale("hi", "IN"));
951
952        String out = "";
953        long l = 1876543210L;
954        out = g.format(l);
955
956        // expect "1,87,65,43,210", but with Hindi digits
957        //         01234567890123
958        boolean ok = true;
959        if (out.length() != 14) {
960            ok = false;
961        } else {
962            for (int i = 0; i < out.length(); ++i) {
963                boolean expectGroup = false;
964                switch (i) {
965                case 1 :
966                case 4 :
967                case 7 :
968                case 10 :
969                    expectGroup = true;
970                    break;
971                }
972                // Later -- fix this to get the actual grouping
973                // character from the resource bundle.
974                boolean isGroup = (out.charAt(i) == 0x002C);
975                if (isGroup != expectGroup) {
976                    ok = false;
977                    break;
978                }
979            }
980        }
981        if (!ok) {
982            errln("FAIL  Expected "+ l + " x hi_IN . \"1,87,65,43,210\" (with Hindi digits), got \""
983                    + out + "\"");
984        } else {
985            logln("Ok    " + l + " x hi_IN . \"" + out + "\"");
986        }
987    }
988
989    public void roundingTest(NumberFormat nf, double x, int maxFractionDigits, final String expected) {
990        nf.setMaximumFractionDigits(maxFractionDigits);
991        String out = nf.format(x);
992        logln(x + " formats with " + maxFractionDigits + " fractional digits to " + out);
993        if (!out.equals(expected))
994            errln("FAIL: Expected " + expected);
995    }
996
997    /**
998     * Upgrade to alphaWorks
999     */
1000    public void TestExponent() {
1001        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1002        DecimalFormat fmt1 = new DecimalFormat("0.###E0", US);
1003        DecimalFormat fmt2 = new DecimalFormat("0.###E+0", US);
1004        int n = 1234;
1005        expect2(fmt1, n, "1.234E3");
1006        expect2(fmt2, n, "1.234E+3");
1007        expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
1008
1009    }
1010
1011    /**
1012     * Upgrade to alphaWorks
1013     */
1014    public void TestScientific() {
1015
1016        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1017
1018        // Test pattern round-trip
1019        final String PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000", "0.###E0;[0.###E0]" };
1020        int PAT_length = PAT.length;
1021        int DIGITS[] = {
1022                // min int, max int, min frac, max frac
1023                0, 1, 0, 0, // "#E0"
1024                1, 1, 0, 4, // "0.####E0"
1025                2, 2, 3, 3, // "00.000E00"
1026                1, 3, 0, 4, // "##0.####E000"
1027                1, 1, 0, 3, // "0.###E0;[0.###E0]"
1028        };
1029        for (int i = 0; i < PAT_length; ++i) {
1030            String pat = PAT[i];
1031            DecimalFormat df = new DecimalFormat(pat, US);
1032            String pat2 = df.toPattern();
1033            if (pat.equals(pat2)) {
1034                logln("Ok   Pattern rt \"" + pat + "\" . \"" + pat2 + "\"");
1035            } else {
1036                errln("FAIL Pattern rt \"" + pat + "\" . \"" + pat2 + "\"");
1037            }
1038            // Make sure digit counts match what we expect
1039            if (df.getMinimumIntegerDigits() != DIGITS[4 * i]
1040                    || df.getMaximumIntegerDigits() != DIGITS[4 * i + 1]
1041                            || df.getMinimumFractionDigits() != DIGITS[4 * i + 2]
1042                                    || df.getMaximumFractionDigits() != DIGITS[4 * i + 3]) {
1043                errln("FAIL \""+ pat+ "\" min/max int; min/max frac = "
1044                        + df.getMinimumIntegerDigits() + "/"
1045                        + df.getMaximumIntegerDigits() + ";"
1046                        + df.getMinimumFractionDigits() + "/"
1047                        + df.getMaximumFractionDigits() + ", expect "
1048                        + DIGITS[4 * i] + "/"
1049                        + DIGITS[4 * i + 1] + ";"
1050                        + DIGITS[4 * i + 2] + "/"
1051                        + DIGITS[4 * i + 3]);
1052            }
1053        }
1054
1055        expect2(new DecimalFormat("#E0", US), 12345.0, "1.2345E4");
1056        expect(new DecimalFormat("0E0", US), 12345.0, "1E4");
1057
1058        // pattern of NumberFormat.getScientificInstance(Locale.US) = "0.######E0" not "#E0"
1059        // so result = 1.234568E4 not 1.2345678901E4
1060        //when the pattern problem is finalized, delete comment mark'//'
1061        //of the following code
1062        expect2(NumberFormat.getScientificInstance(Locale.US), 12345.678901, "1.2345678901E4");
1063        logln("Testing NumberFormat.getScientificInstance(ULocale) ...");
1064        expect2(NumberFormat.getScientificInstance(ULocale.US), 12345.678901, "1.2345678901E4");
1065
1066        expect(new DecimalFormat("##0.###E0", US), 12345.0, "12.34E3");
1067        expect(new DecimalFormat("##0.###E0", US), 12345.00001, "12.35E3");
1068        expect2(new DecimalFormat("##0.####E0", US), 12345, "12.345E3");
1069
1070        // pattern of NumberFormat.getScientificInstance(Locale.US) = "0.######E0" not "#E0"
1071        // so result = 1.234568E4 not 1.2345678901E4
1072        expect2(NumberFormat.getScientificInstance(Locale.FRANCE), 12345.678901, "1,2345678901E4");
1073        logln("Testing NumberFormat.getScientificInstance(ULocale) ...");
1074        expect2(NumberFormat.getScientificInstance(ULocale.FRANCE), 12345.678901, "1,2345678901E4");
1075
1076        expect(new DecimalFormat("##0.####E0", US), 789.12345e-9, "789.12E-9");
1077        expect2(new DecimalFormat("##0.####E0", US), 780.e-9, "780E-9");
1078        expect(new DecimalFormat(".###E0", US), 45678.0, ".457E5");
1079        expect2(new DecimalFormat(".###E0", US), 0, ".0E0");
1080        /*
1081        expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
1082                                     new DecimalFormat("##E0", US),
1083                                     new DecimalFormat("####E0", US),
1084                                     new DecimalFormat("0E0", US),
1085                                     new DecimalFormat("00E0", US),
1086                                     new DecimalFormat("000E0", US),
1087                                   },
1088               new Long(45678000),
1089               new String[] { "4.5678E7",
1090                              "45.678E6",
1091                              "4567.8E4",
1092                              "5E7",
1093                              "46E6",
1094                              "457E5",
1095                            }
1096               );
1097        !
1098        ! Unroll this test into individual tests below...
1099        !
1100         */
1101        expect2(new DecimalFormat("#E0", US), 45678000, "4.5678E7");
1102        expect2(new DecimalFormat("##E0", US), 45678000, "45.678E6");
1103        expect2(new DecimalFormat("####E0", US), 45678000, "4567.8E4");
1104        expect(new DecimalFormat("0E0", US), 45678000, "5E7");
1105        expect(new DecimalFormat("00E0", US), 45678000, "46E6");
1106        expect(new DecimalFormat("000E0", US), 45678000, "457E5");
1107        /*
1108        expect(new DecimalFormat("###E0", US, status),
1109               new Object[] { new Double(0.0000123), "12.3E-6",
1110                              new Double(0.000123), "123E-6",
1111                              new Double(0.00123), "1.23E-3",
1112                              new Double(0.0123), "12.3E-3",
1113                              new Double(0.123), "123E-3",
1114                              new Double(1.23), "1.23E0",
1115                              new Double(12.3), "12.3E0",
1116                              new Double(123), "123E0",
1117                              new Double(1230), "1.23E3",
1118                             });
1119        !
1120        ! Unroll this test into individual tests below...
1121        !
1122         */
1123        expect2(new DecimalFormat("###E0", US), 0.0000123, "12.3E-6");
1124        expect2(new DecimalFormat("###E0", US), 0.000123, "123E-6");
1125        expect2(new DecimalFormat("###E0", US), 0.00123, "1.23E-3");
1126        expect2(new DecimalFormat("###E0", US), 0.0123, "12.3E-3");
1127        expect2(new DecimalFormat("###E0", US), 0.123, "123E-3");
1128        expect2(new DecimalFormat("###E0", US), 1.23, "1.23E0");
1129        expect2(new DecimalFormat("###E0", US), 12.3, "12.3E0");
1130        expect2(new DecimalFormat("###E0", US), 123.0, "123E0");
1131        expect2(new DecimalFormat("###E0", US), 1230.0, "1.23E3");
1132        /*
1133        expect(new DecimalFormat("0.#E+00", US, status),
1134               new Object[] { new Double(0.00012), "1.2E-04",
1135                              new Long(12000),     "1.2E+04",
1136                             });
1137        !
1138        ! Unroll this test into individual tests below...
1139        !
1140         */
1141        expect2(new DecimalFormat("0.#E+00", US), 0.00012, "1.2E-04");
1142        expect2(new DecimalFormat("0.#E+00", US), 12000, "1.2E+04");
1143    }
1144
1145    /**
1146     * Upgrade to alphaWorks
1147     */
1148    public void TestPad() {
1149
1150        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1151        expect2(new DecimalFormat("*^##.##", US), 0, "^^^^0");
1152        expect2(new DecimalFormat("*^##.##", US), -1.3, "^-1.3");
1153        expect2(
1154                new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
1155                0,
1156                "0.0E0______ g-m/s^2");
1157        expect(
1158                new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
1159                1.0 / 3,
1160                "333.333E-3_ g-m/s^2");
1161        expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US), 0, "0.0______ g-m/s^2");
1162        expect(
1163                new DecimalFormat("##0.0####*_ 'g-m/s^2'", US),
1164                1.0 / 3,
1165                "0.33333__ g-m/s^2");
1166
1167        // Test padding before a sign
1168        final String formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
1169        expect2(new DecimalFormat(formatStr, US), -10, "xxxxxxxxxx(10.0)");
1170        expect2(new DecimalFormat(formatStr, US), -1000, "xxxxxxx(1,000.0)");
1171        expect2(new DecimalFormat(formatStr, US), -1000000, "xxx(1,000,000.0)");
1172        expect2(new DecimalFormat(formatStr, US), -100.37, "xxxxxxxx(100.37)");
1173        expect2(new DecimalFormat(formatStr, US), -10456.37, "xxxxx(10,456.37)");
1174        expect2(new DecimalFormat(formatStr, US), -1120456.37, "xx(1,120,456.37)");
1175        expect2(new DecimalFormat(formatStr, US), -112045600.37, "(112,045,600.37)");
1176        expect2(new DecimalFormat(formatStr, US), -1252045600.37, "(1,252,045,600.37)");
1177
1178        expect2(new DecimalFormat(formatStr, US), 10, "xxxxxxxxxxxx10.0");
1179        expect2(new DecimalFormat(formatStr, US), 1000, "xxxxxxxxx1,000.0");
1180        expect2(new DecimalFormat(formatStr, US), 1000000, "xxxxx1,000,000.0");
1181        expect2(new DecimalFormat(formatStr, US), 100.37, "xxxxxxxxxx100.37");
1182        expect2(new DecimalFormat(formatStr, US), 10456.37, "xxxxxxx10,456.37");
1183        expect2(new DecimalFormat(formatStr, US), 1120456.37, "xxxx1,120,456.37");
1184        expect2(new DecimalFormat(formatStr, US), 112045600.37, "xx112,045,600.37");
1185        expect2(new DecimalFormat(formatStr, US), 10252045600.37, "10,252,045,600.37");
1186
1187        // Test padding between a sign and a number
1188        final String formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
1189        expect2(new DecimalFormat(formatStr2, US), -10, "(10.0xxxxxxxxxx)");
1190        expect2(new DecimalFormat(formatStr2, US), -1000, "(1,000.0xxxxxxx)");
1191        expect2(new DecimalFormat(formatStr2, US), -1000000, "(1,000,000.0xxx)");
1192        expect2(new DecimalFormat(formatStr2, US), -100.37, "(100.37xxxxxxxx)");
1193        expect2(new DecimalFormat(formatStr2, US), -10456.37, "(10,456.37xxxxx)");
1194        expect2(new DecimalFormat(formatStr2, US), -1120456.37, "(1,120,456.37xx)");
1195        expect2(new DecimalFormat(formatStr2, US), -112045600.37, "(112,045,600.37)");
1196        expect2(new DecimalFormat(formatStr2, US), -1252045600.37, "(1,252,045,600.37)");
1197
1198        expect2(new DecimalFormat(formatStr2, US), 10, "10.0xxxxxxxxxxxx");
1199        expect2(new DecimalFormat(formatStr2, US), 1000, "1,000.0xxxxxxxxx");
1200        expect2(new DecimalFormat(formatStr2, US), 1000000, "1,000,000.0xxxxx");
1201        expect2(new DecimalFormat(formatStr2, US), 100.37, "100.37xxxxxxxxxx");
1202        expect2(new DecimalFormat(formatStr2, US), 10456.37, "10,456.37xxxxxxx");
1203        expect2(new DecimalFormat(formatStr2, US), 1120456.37, "1,120,456.37xxxx");
1204        expect2(new DecimalFormat(formatStr2, US), 112045600.37, "112,045,600.37xx");
1205        expect2(new DecimalFormat(formatStr2, US), 10252045600.37, "10,252,045,600.37");
1206
1207        //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
1208        DecimalFormat fmt = new DecimalFormat("#", US);
1209        char padString = 'P';
1210        fmt.setPadCharacter(padString);
1211        expectPad(fmt, "*P##.##", DecimalFormat.PAD_BEFORE_PREFIX, 5, padString);
1212        fmt.setPadCharacter('^');
1213        expectPad(fmt, "*^#", DecimalFormat.PAD_BEFORE_PREFIX, 1, '^');
1214        //commented untill implementation is complete
1215        /*  fmt.setPadCharacter((UnicodeString)"^^^");
1216          expectPad(fmt, "*^^^#", DecimalFormat.kPadBeforePrefix, 3, (UnicodeString)"^^^");
1217          padString.remove();
1218          padString.append((UChar)0x0061);
1219          padString.append((UChar)0x0302);
1220          fmt.setPadCharacter(padString);
1221          UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
1222          UnicodeString pattern(patternChars);
1223          expectPad(fmt, pattern , DecimalFormat.kPadBeforePrefix, 4, padString);
1224         */
1225    }
1226
1227    /**
1228     * Upgrade to alphaWorks
1229     */
1230    public void TestPatterns2() {
1231        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1232        DecimalFormat fmt = new DecimalFormat("#", US);
1233
1234        char hat = 0x005E; /*^*/
1235
1236        expectPad(fmt, "*^#", DecimalFormat.PAD_BEFORE_PREFIX, 1, hat);
1237        expectPad(fmt, "$*^#", DecimalFormat.PAD_AFTER_PREFIX, 2, hat);
1238        expectPad(fmt, "#*^", DecimalFormat.PAD_BEFORE_SUFFIX, 1, hat);
1239        expectPad(fmt, "#$*^", DecimalFormat.PAD_AFTER_SUFFIX, 2, hat);
1240        expectPad(fmt, "$*^$#", -1);
1241        expectPad(fmt, "#$*^$", -1);
1242        expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat.PAD_BEFORE_SUFFIX, 12, (char) 0x0078 /*x*/);
1243        expectPad(fmt, "''#0*x", DecimalFormat.PAD_BEFORE_SUFFIX, 3, (char) 0x0078 /*x*/);
1244        expectPad(fmt, "'I''ll'*a###.##", DecimalFormat.PAD_AFTER_PREFIX, 10, (char) 0x0061 /*a*/);
1245
1246        fmt.applyPattern("AA#,##0.00ZZ");
1247        fmt.setPadCharacter(hat);
1248
1249        fmt.setFormatWidth(10);
1250
1251        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_PREFIX);
1252        expectPat(fmt, "*^AA#,##0.00ZZ");
1253
1254        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_SUFFIX);
1255        expectPat(fmt, "AA#,##0.00*^ZZ");
1256
1257        fmt.setPadPosition(DecimalFormat.PAD_AFTER_SUFFIX);
1258        expectPat(fmt, "AA#,##0.00ZZ*^");
1259
1260        //            12  3456789012
1261        String exp = "AA*^#,##0.00ZZ";
1262        fmt.setFormatWidth(12);
1263        fmt.setPadPosition(DecimalFormat.PAD_AFTER_PREFIX);
1264        expectPat(fmt, exp);
1265
1266        fmt.setFormatWidth(13);
1267        //              12  34567890123
1268        expectPat(fmt, "AA*^##,##0.00ZZ");
1269
1270        fmt.setFormatWidth(14);
1271        //              12  345678901234
1272        expectPat(fmt, "AA*^###,##0.00ZZ");
1273
1274        fmt.setFormatWidth(15);
1275        //              12  3456789012345
1276        expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
1277
1278        fmt.setFormatWidth(16);
1279        //              12  34567890123456
1280        expectPat(fmt, "AA*^#,###,##0.00ZZ");
1281    }
1282
1283    public void TestRegistration() {
1284        final ULocale SRC_LOC = ULocale.FRANCE;
1285        final ULocale SWAP_LOC = ULocale.US;
1286
1287        class TestFactory extends SimpleNumberFormatFactory {
1288            NumberFormat currencyStyle;
1289
1290            TestFactory() {
1291                super(SRC_LOC, true);
1292                currencyStyle = NumberFormat.getIntegerInstance(SWAP_LOC);
1293            }
1294
1295            @Override
1296            public NumberFormat createFormat(ULocale loc, int formatType) {
1297                if (formatType == FORMAT_CURRENCY) {
1298                    return currencyStyle;
1299                }
1300                return null;
1301            }
1302        }
1303
1304        NumberFormat f0 = NumberFormat.getIntegerInstance(SWAP_LOC);
1305        NumberFormat f1 = NumberFormat.getIntegerInstance(SRC_LOC);
1306        NumberFormat f2 = NumberFormat.getCurrencyInstance(SRC_LOC);
1307        Object key = NumberFormat.registerFactory(new TestFactory());
1308        NumberFormat f3 = NumberFormat.getCurrencyInstance(SRC_LOC);
1309        NumberFormat f4 = NumberFormat.getIntegerInstance(SRC_LOC);
1310        NumberFormat.unregister(key); // restore for other tests
1311        NumberFormat f5 = NumberFormat.getCurrencyInstance(SRC_LOC);
1312
1313        float n = 1234.567f;
1314        logln("f0 swap int: " + f0.format(n));
1315        logln("f1 src int: " + f1.format(n));
1316        logln("f2 src cur: " + f2.format(n));
1317        logln("f3 reg cur: " + f3.format(n));
1318        logln("f4 reg int: " + f4.format(n));
1319        logln("f5 unreg cur: " + f5.format(n));
1320
1321        if (!f3.format(n).equals(f0.format(n))) {
1322            errln("registered service did not match");
1323        }
1324        if (!f4.format(n).equals(f1.format(n))) {
1325            errln("registered service did not inherit");
1326        }
1327        if (!f5.format(n).equals(f2.format(n))) {
1328            errln("unregistered service did not match original");
1329        }
1330    }
1331
1332    public void TestScientific2() {
1333        // jb 2552
1334        DecimalFormat fmt = (DecimalFormat)NumberFormat.getCurrencyInstance();
1335        Number num = new Double(12.34);
1336        expect(fmt, num, "$12.34");
1337        fmt.setScientificNotation(true);
1338        expect(fmt, num, "$1.23E1");
1339        fmt.setScientificNotation(false);
1340        expect(fmt, num, "$12.34");
1341    }
1342
1343    public void TestScientificGrouping() {
1344        // jb 2552
1345        DecimalFormat fmt = new DecimalFormat("###.##E0");
1346        expect(fmt, .01234, "12.3E-3");
1347        expect(fmt, .1234, "123E-3");
1348        expect(fmt, 1.234, "1.23E0");
1349        expect(fmt, 12.34, "12.3E0");
1350        expect(fmt, 123.4, "123E0");
1351        expect(fmt, 1234, "1.23E3");
1352    }
1353
1354    // additional coverage tests
1355
1356    // sigh, can't have static inner classes, why not?
1357
1358    static final class PI extends Number {
1359        /**
1360         * For serialization
1361         */
1362        private static final long serialVersionUID = -305601227915602172L;
1363
1364        private PI() {}
1365        @Override
1366        public int intValue() { return (int)Math.PI; }
1367        @Override
1368        public long longValue() { return (long)Math.PI; }
1369        @Override
1370        public float  floatValue() { return (float)Math.PI; }
1371        @Override
1372        public double doubleValue() { return Math.PI; }
1373        @Override
1374        public byte byteValue() { return (byte)Math.PI; }
1375        @Override
1376        public short shortValue() { return (short)Math.PI; }
1377
1378        public static final Number INSTANCE = new PI();
1379    }
1380
1381    public void TestCoverage() {
1382        NumberFormat fmt = NumberFormat.getNumberInstance(); // default locale
1383        logln(fmt.format(new BigInteger("1234567890987654321234567890987654321", 10)));
1384
1385        fmt = NumberFormat.getScientificInstance(); // default locale
1386
1387        logln(fmt.format(PI.INSTANCE));
1388
1389        try {
1390            logln(fmt.format("12345"));
1391            errln("numberformat of string did not throw exception");
1392        }
1393        catch (Exception e) {
1394            logln("PASS: numberformat of string failed as expected");
1395        }
1396
1397        int hash = fmt.hashCode();
1398        logln("hash code " + hash);
1399
1400        logln("compare to string returns: " + fmt.equals(""));
1401
1402        // For ICU 2.6 - alan
1403        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1404        DecimalFormat df = new DecimalFormat("'*&'' '\u00A4' ''&*' #,##0.00", US);
1405        df.setCurrency(Currency.getInstance("INR"));
1406        expect2(df, 1.0, "*&' \u20B9 '&* 1.00");
1407        expect2(df, -2.0, "-*&' \u20B9 '&* 2.00");
1408        df.applyPattern("#,##0.00 '*&'' '\u00A4' ''&*'");
1409        expect2(df, 2.0, "2.00 *&' \u20B9 '&*");
1410        expect2(df, -1.0, "-1.00 *&' \u20B9 '&*");
1411
1412        java.math.BigDecimal r;
1413
1414        r = df.getRoundingIncrement();
1415        if (r != null) {
1416            errln("FAIL: rounding = " + r + ", expect null");
1417        }
1418
1419        if (df.isScientificNotation()) {
1420            errln("FAIL: isScientificNotation = true, expect false");
1421        }
1422
1423        df.applyPattern("0.00000");
1424        df.setScientificNotation(true);
1425        if (!df.isScientificNotation()) {
1426            errln("FAIL: isScientificNotation = false, expect true");
1427        }
1428        df.setMinimumExponentDigits((byte)2);
1429        if (df.getMinimumExponentDigits() != 2) {
1430            errln("FAIL: getMinimumExponentDigits = " +
1431                    df.getMinimumExponentDigits() + ", expect 2");
1432        }
1433        df.setExponentSignAlwaysShown(true);
1434        if (!df.isExponentSignAlwaysShown()) {
1435            errln("FAIL: isExponentSignAlwaysShown = false, expect true");
1436        }
1437        df.setSecondaryGroupingSize(0);
1438        if (df.getSecondaryGroupingSize() != 0) {
1439            errln("FAIL: getSecondaryGroupingSize = " +
1440                    df.getSecondaryGroupingSize() + ", expect 0");
1441        }
1442        expect2(df, 3.14159, "3.14159E+00");
1443
1444        // DecimalFormatSymbols#getInstance
1445        DecimalFormatSymbols decsym1 = DecimalFormatSymbols.getInstance();
1446        DecimalFormatSymbols decsym2 = new DecimalFormatSymbols();
1447        if (!decsym1.equals(decsym2)) {
1448            errln("FAIL: DecimalFormatSymbols returned by getInstance()" +
1449                    "does not match new DecimalFormatSymbols().");
1450        }
1451        decsym1 = DecimalFormatSymbols.getInstance(Locale.JAPAN);
1452        decsym2 = DecimalFormatSymbols.getInstance(ULocale.JAPAN);
1453        if (!decsym1.equals(decsym2)) {
1454            errln("FAIL: DecimalFormatSymbols returned by getInstance(Locale.JAPAN)" +
1455                    "does not match the one returned by getInstance(ULocale.JAPAN).");
1456        }
1457
1458        // DecimalFormatSymbols#getAvailableLocales/#getAvailableULocales
1459        Locale[] allLocales = DecimalFormatSymbols.getAvailableLocales();
1460        if (allLocales.length == 0) {
1461            errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1462        } else {
1463            logln("PASS: " + allLocales.length +
1464                    " available locales returned by DecimalFormatSymbols.getAvailableLocales");
1465        }
1466        ULocale[] allULocales = DecimalFormatSymbols.getAvailableULocales();
1467        if (allULocales.length == 0) {
1468            errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1469        } else {
1470            logln("PASS: " + allULocales.length +
1471                    " available locales returned by DecimalFormatSymbols.getAvailableULocales");
1472        }
1473    }
1474
1475    public void TestWhiteSpaceParsing() {
1476        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1477        DecimalFormat fmt = new DecimalFormat("a  b#0c  ", US);
1478        int n = 1234;
1479        expect(fmt, "a b1234c ", n);
1480        expect(fmt, "a   b1234c   ", n);
1481    }
1482
1483    /**
1484     * Test currencies whose display name is a ChoiceFormat.
1485     */
1486    public void TestComplexCurrency() {
1487        //  CLDR No Longer uses complex currency symbols.
1488        //  Skipping this test.
1489        //        Locale loc = new Locale("kn", "IN", "");
1490        //        NumberFormat fmt = NumberFormat.getCurrencyInstance(loc);
1491
1492        //        expect2(fmt, 1.0, "Re.\u00a01.00");
1493        //        expect(fmt, 1.001, "Re.\u00a01.00"); // tricky
1494        //        expect2(fmt, 12345678.0, "Rs.\u00a01,23,45,678.00");
1495        //        expect2(fmt, 0.5, "Rs.\u00a00.50");
1496        //        expect2(fmt, -1.0, "-Re.\u00a01.00");
1497        //        expect2(fmt, -10.0, "-Rs.\u00a010.00");
1498    }
1499
1500    public void TestCurrencyKeyword() {
1501        ULocale locale = new ULocale("th_TH@currency=QQQ");
1502        NumberFormat format = NumberFormat.getCurrencyInstance(locale);
1503        String result = format.format(12.34f);
1504        if (!"QQQ12.34".equals(result)) {
1505            errln("got unexpected currency: " + result);
1506        }
1507    }
1508
1509    /**
1510     * Test alternate numbering systems
1511     */
1512    public void TestNumberingSystems() {
1513        class TestNumberingSystemItem {
1514            private final String localeName;
1515            private final double value;
1516            private final boolean isRBNF;
1517            private final String expectedResult;
1518
1519            TestNumberingSystemItem(String loc, double val, boolean rbnf, String exp) {
1520                localeName  = loc;
1521                value = val;
1522                isRBNF = rbnf;
1523                expectedResult = exp;
1524            }
1525        }
1526
1527        final TestNumberingSystemItem[] DATA = {
1528                new TestNumberingSystemItem( "en_US@numbers=thai",        1234.567, false, "\u0e51,\u0e52\u0e53\u0e54.\u0e55\u0e56\u0e57" ),
1529                new TestNumberingSystemItem( "en_US@numbers=thai",        1234.567, false, "\u0E51,\u0E52\u0E53\u0E54.\u0E55\u0E56\u0E57" ),
1530                new TestNumberingSystemItem( "en_US@numbers=hebr",        5678.0,   true,  "\u05D4\u05F3\u05EA\u05E8\u05E2\u05F4\u05D7" ),
1531                new TestNumberingSystemItem( "en_US@numbers=arabext",     1234.567, false, "\u06F1\u066c\u06F2\u06F3\u06F4\u066b\u06F5\u06F6\u06F7" ),
1532                new TestNumberingSystemItem( "de_DE@numbers=foobar",      1234.567, false, "1.234,567" ),
1533                new TestNumberingSystemItem( "ar_EG",                     1234.567, false, "\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666\u0667" ),
1534                new TestNumberingSystemItem( "th_TH@numbers=traditional", 1234.567, false, "\u0E51,\u0E52\u0E53\u0E54.\u0E55\u0E56\u0E57" ), // fall back to native per TR35
1535                new TestNumberingSystemItem( "ar_MA",                     1234.567, false, "1.234,567" ),
1536                new TestNumberingSystemItem( "en_US@numbers=hanidec",     1234.567, false, "\u4e00,\u4e8c\u4e09\u56db.\u4e94\u516d\u4e03" ),
1537                new TestNumberingSystemItem( "ta_IN@numbers=native",      1234.567, false, "\u0BE7,\u0BE8\u0BE9\u0BEA.\u0BEB\u0BEC\u0BED" ),
1538                new TestNumberingSystemItem( "ta_IN@numbers=traditional", 1235.0,   true,  "\u0BF2\u0BE8\u0BF1\u0BE9\u0BF0\u0BEB" ),
1539                new TestNumberingSystemItem( "ta_IN@numbers=finance",     1234.567, false, "1,234.567" ), // fall back to default per TR35
1540                new TestNumberingSystemItem( "zh_TW@numbers=native",      1234.567, false, "\u4e00,\u4e8c\u4e09\u56db.\u4e94\u516d\u4e03" ),
1541                new TestNumberingSystemItem( "zh_TW@numbers=traditional", 1234.567, true,  "\u4E00\u5343\u4E8C\u767E\u4E09\u5341\u56DB\u9EDE\u4E94\u516D\u4E03" ),
1542                new TestNumberingSystemItem( "zh_TW@numbers=finance",     1234.567, true,  "\u58F9\u4EDF\u8CB3\u4F70\u53C3\u62FE\u8086\u9EDE\u4F0D\u9678\u67D2" )
1543        };
1544
1545
1546        for (TestNumberingSystemItem item : DATA) {
1547            ULocale loc = new ULocale(item.localeName);
1548            NumberFormat fmt = NumberFormat.getInstance(loc);
1549            if (item.isRBNF) {
1550                expect3(fmt,item.value,item.expectedResult);
1551            } else {
1552                expect2(fmt,item.value,item.expectedResult);
1553            }
1554        }
1555    }
1556
1557    public void Test6816() {
1558        Currency cur1 = Currency.getInstance(new Locale("und", "PH"));
1559
1560        NumberFormat nfmt = NumberFormat.getCurrencyInstance(new Locale("und", "PH"));
1561        DecimalFormatSymbols decsym = ((DecimalFormat)nfmt).getDecimalFormatSymbols();
1562        Currency cur2 = decsym.getCurrency();
1563
1564        if ( !cur1.getCurrencyCode().equals("PHP") || !cur2.getCurrencyCode().equals("PHP")) {
1565            errln("FAIL: Currencies should match PHP: cur1 = "+cur1.getCurrencyCode()+"; cur2 = "+cur2.getCurrencyCode());
1566        }
1567
1568    }
1569
1570    public void TestThreadedFormat() {
1571
1572        class FormatTask implements Runnable {
1573            DecimalFormat fmt;
1574            StringBuffer buf;
1575            boolean inc;
1576            float num;
1577
1578            FormatTask(DecimalFormat fmt, int index) {
1579                this.fmt = fmt;
1580                this.buf = new StringBuffer();
1581                this.inc = (index & 0x1) == 0;
1582                this.num = inc ? 0 : 10000;
1583            }
1584
1585            public void run() {
1586                if (inc) {
1587                    while (num < 10000) {
1588                        buf.append(fmt.format(num) + "\n");
1589                        num += 3.14159;
1590                    }
1591                } else {
1592                    while (num > 0) {
1593                        buf.append(fmt.format(num) + "\n");
1594                        num -= 3.14159;
1595                    }
1596                }
1597            }
1598
1599            String result() {
1600                return buf.toString();
1601            }
1602        }
1603
1604        DecimalFormat fmt = new DecimalFormat("0.####");
1605        FormatTask[] tasks = new FormatTask[8];
1606        for (int i = 0; i < tasks.length; ++i) {
1607            tasks[i] = new FormatTask(fmt, i);
1608        }
1609
1610        TestUtil.runUntilDone(tasks);
1611
1612        for (int i = 2; i < tasks.length; i++) {
1613            String str1 = tasks[i].result();
1614            String str2 = tasks[i-2].result();
1615            if (!str1.equals(str2)) {
1616                System.out.println("mismatch at " + i);
1617                System.out.println(str1);
1618                System.out.println(str2);
1619                errln("decimal format thread mismatch");
1620
1621                break;
1622            }
1623            str1 = str2;
1624        }
1625    }
1626
1627    public void TestPerMill() {
1628        DecimalFormat fmt = new DecimalFormat("###.###\u2030");
1629        assertEquals("0.4857 x ###.###\u2030",
1630                "485.7\u2030", fmt.format(0.4857));
1631
1632        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.ENGLISH);
1633        sym.setPerMill('m');
1634        DecimalFormat fmt2 = new DecimalFormat("", sym);
1635        fmt2.applyLocalizedPattern("###.###m");
1636        assertEquals("0.4857 x ###.###m",
1637                "485.7m", fmt2.format(0.4857));
1638    }
1639
1640    public void TestIllegalPatterns() {
1641        // Test cases:
1642        // Prefix with "-:" for illegal patterns
1643        // Prefix with "+:" for legal patterns
1644        String DATA[] = {
1645                // Unquoted special characters in the suffix are illegal
1646                "-:000.000|###",
1647                "+:000.000'|###'",
1648        };
1649        for (int i=0; i<DATA.length; ++i) {
1650            String pat=DATA[i];
1651            boolean valid = pat.charAt(0) == '+';
1652            pat = pat.substring(2);
1653            Exception e = null;
1654            try {
1655                // locale doesn't matter here
1656                new DecimalFormat(pat);
1657            } catch (IllegalArgumentException e1) {
1658                e = e1;
1659            } catch (IndexOutOfBoundsException e1) {
1660                e = e1;
1661            }
1662            String msg = (e==null) ? "success" : e.getMessage();
1663            if ((e==null) == valid) {
1664                logln("Ok: pattern \"" + pat + "\": " + msg);
1665            } else {
1666                errln("FAIL: pattern \"" + pat + "\" should have " +
1667                        (valid?"succeeded":"failed") + "; got " + msg);
1668            }
1669        }
1670    }
1671
1672    /**
1673     * Parse a CurrencyAmount using the given NumberFormat, with
1674     * the 'delim' character separating the number and the currency.
1675     */
1676    private static CurrencyAmount parseCurrencyAmount(String str, NumberFormat fmt,
1677            char delim)
1678                    throws ParseException {
1679        int i = str.indexOf(delim);
1680        return new CurrencyAmount(fmt.parse(str.substring(0,i)),
1681                Currency.getInstance(str.substring(i+1)));
1682    }
1683
1684    /**
1685     * Return an integer representing the next token from this
1686     * iterator.  The integer will be an index into the given list, or
1687     * -1 if there are no more tokens, or -2 if the token is not on
1688     * the list.
1689     */
1690    private static int keywordIndex(String tok) {
1691        for (int i=0; i<KEYWORDS.length; ++i) {
1692            if (tok.equals(KEYWORDS[i])) {
1693                return i;
1694            }
1695        }
1696        return -1;
1697    }
1698
1699    private static final String KEYWORDS[] = {
1700        /*0*/ "ref=", // <reference pattern to parse numbers>
1701        /*1*/ "loc=", // <locale for formats>
1702        /*2*/ "f:",   // <pattern or '-'> <number> <exp. string>
1703        /*3*/ "fp:",  // <pattern or '-'> <number> <exp. string> <exp. number>
1704        /*4*/ "rt:",  // <pattern or '-'> <(exp.) number> <(exp.) string>
1705        /*5*/ "p:",   // <pattern or '-'> <string> <exp. number>
1706        /*6*/ "perr:", // <pattern or '-'> <invalid string>
1707        /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
1708        /*8*/ "fpc:", // <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
1709        /*9*/ "strict=", // true or false
1710    };
1711
1712    @SuppressWarnings("resource")  // InputStream is will be closed by the ResourceReader.
1713    public void TestCases() {
1714        String caseFileName = "NumberFormatTestCases.txt";
1715        java.io.InputStream is = NumberFormatTest.class.getResourceAsStream(caseFileName);
1716
1717        ResourceReader reader = new ResourceReader(is, caseFileName, "utf-8");
1718        TokenIterator tokens = new TokenIterator(reader);
1719
1720        Locale loc = new Locale("en", "US", "");
1721        DecimalFormat ref = null, fmt = null;
1722        MeasureFormat mfmt = null;
1723        String pat = null, str = null, mloc = null;
1724        boolean strict = false;
1725
1726        try {
1727            for (;;) {
1728                String tok = tokens.next();
1729                if (tok == null) {
1730                    break;
1731                }
1732                String where = "(" + tokens.getLineNumber() + ") ";
1733                int cmd = keywordIndex(tok);
1734                switch (cmd) {
1735                case 0:
1736                    // ref= <reference pattern>
1737                    ref = new DecimalFormat(tokens.next(),
1738                            new DecimalFormatSymbols(Locale.US));
1739                    ref.setParseStrict(strict);
1740                    logln("Setting reference pattern to:\t" + ref);
1741                    break;
1742                case 1:
1743                    // loc= <locale>
1744                    loc = LocaleUtility.getLocaleFromName(tokens.next());
1745                    pat = ((DecimalFormat) NumberFormat.getInstance(loc)).toPattern();
1746                    logln("Setting locale to:\t" + loc + ", \tand pattern to:\t" + pat);
1747                    break;
1748                case 2: // f:
1749                case 3: // fp:
1750                case 4: // rt:
1751                case 5: // p:
1752                    tok = tokens.next();
1753                    if (!tok.equals("-")) {
1754                        pat = tok;
1755                    }
1756                    try {
1757                        fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc));
1758                        fmt.setParseStrict(strict);
1759                    } catch (IllegalArgumentException iae) {
1760                        errln(where + "Pattern \"" + pat + '"');
1761                        iae.printStackTrace();
1762                        tokens.next(); // consume remaining tokens
1763                        //tokens.next();
1764                        if (cmd == 3) tokens.next();
1765                        continue;
1766                    }
1767                    str = null;
1768                    try {
1769                        if (cmd == 2 || cmd == 3 || cmd == 4) {
1770                            // f: <pattern or '-'> <number> <exp. string>
1771                            // fp: <pattern or '-'> <number> <exp. string> <exp. number>
1772                            // rt: <pattern or '-'> <number> <string>
1773                            String num = tokens.next();
1774                            str = tokens.next();
1775                            Number n = ref.parse(num);
1776                            assertEquals(where + '"' + pat + "\".format(" + num + ")",
1777                                    str, fmt.format(n));
1778                            if (cmd == 3) { // fp:
1779                                n = ref.parse(tokens.next());
1780                            }
1781                            if (cmd != 2) { // != f:
1782                                assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
1783                                        n, fmt.parse(str));
1784                            }
1785                        }
1786                        // p: <pattern or '-'> <string to parse> <exp. number>
1787                        else {
1788                            str = tokens.next();
1789                            String expstr = tokens.next();
1790                            Number parsed = fmt.parse(str);
1791                            Number exp = ref.parse(expstr);
1792                            assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
1793                                    exp, parsed);
1794                        }
1795                    } catch (ParseException e) {
1796                        errln(where + '"' + pat + "\".parse(\"" + str +
1797                                "\") threw an exception");
1798                        e.printStackTrace();
1799                    }
1800                    break;
1801                case 6:
1802                    // perr: <pattern or '-'> <invalid string>
1803                    errln("Under construction");
1804                    return;
1805                case 7:
1806                    // pat: <pattern> <exp. toPattern, or '-' or 'err'>
1807                    String testpat = tokens.next();
1808                    String exppat  = tokens.next();
1809                    boolean err    = exppat.equals("err");
1810                    if (testpat.equals("-")) {
1811                        if (err) {
1812                            errln("Invalid command \"pat: - err\" at " +  tokens.describePosition());
1813                            continue;
1814                        }
1815                        testpat = pat;
1816                    }
1817                    if (exppat.equals("-")) exppat = testpat;
1818                    try {
1819                        DecimalFormat f = null;
1820                        if (testpat == pat) { // [sic]
1821                            f = fmt;
1822                        } else {
1823                            f = new DecimalFormat(testpat);
1824                            f.setParseStrict(strict);
1825                        }
1826                        if (err) {
1827                            errln(where + "Invalid pattern \"" + testpat +
1828                                    "\" was accepted");
1829                        } else {
1830                            assertEquals(where + '"' + testpat + "\".toPattern()",
1831                                    exppat, f.toPattern());
1832                        }
1833                    } catch (IllegalArgumentException iae2) {
1834                        if (err) {
1835                            logln("Ok: " + where + "Invalid pattern \"" + testpat +
1836                                    "\" threw an exception");
1837                        } else {
1838                            errln(where + "Valid pattern \"" + testpat +
1839                                    "\" threw an exception");
1840                            iae2.printStackTrace();
1841                        }
1842                    }
1843                    break;
1844                case 8: // fpc:
1845                    tok = tokens.next();
1846                    if (!tok.equals("-")) {
1847                        mloc = tok;
1848                        ULocale l = new ULocale(mloc);
1849                        try {
1850                            mfmt = MeasureFormat.getCurrencyFormat(l);
1851                        } catch (IllegalArgumentException iae) {
1852                            errln(where + "Loc \"" + tok + '"');
1853                            iae.printStackTrace();
1854                            tokens.next(); // consume remaining tokens
1855                            tokens.next();
1856                            tokens.next();
1857                            continue;
1858                        }
1859                    }
1860                    str = null;
1861                    try {
1862                        // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
1863                        String currAmt = tokens.next();
1864                        str = tokens.next();
1865                        CurrencyAmount target = parseCurrencyAmount(currAmt, ref, '/');
1866                        String formatResult = mfmt.format(target);
1867                        assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
1868                                str, formatResult);
1869                        target = parseCurrencyAmount(tokens.next(), ref, '/');
1870                        CurrencyAmount parseResult = (CurrencyAmount) mfmt.parseObject(str);
1871                        assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
1872                                target, parseResult);
1873                    } catch (ParseException e) {
1874                        errln(where + '"' + pat + "\".parse(\"" + str +
1875                                "\") threw an exception");
1876                        e.printStackTrace();
1877                    }
1878                    break;
1879                case 9: // strict= true or false
1880                    strict = "true".equalsIgnoreCase(tokens.next());
1881                    logln("Setting strict to:\t" + strict);
1882                    break;
1883                case -1:
1884                    errln("Unknown command \"" + tok + "\" at " + tokens.describePosition());
1885                    return;
1886                }
1887            }
1888        } catch (java.io.IOException e) {
1889            throw new RuntimeException(e);
1890        } finally {
1891            try {
1892                reader.close();
1893            } catch (IOException ignored) {
1894            }
1895        }
1896    }
1897
1898    public void TestFieldPositionDecimal() {
1899        DecimalFormat nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1900        nf.setPositivePrefix("FOO");
1901        nf.setPositiveSuffix("BA");
1902        StringBuffer buffer = new StringBuffer();
1903        FieldPosition fp = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
1904        nf.format(35.47, buffer, fp);
1905        assertEquals("35.47", "FOO35.47BA", buffer.toString());
1906        assertEquals("fp begin", 5, fp.getBeginIndex());
1907        assertEquals("fp end", 6, fp.getEndIndex());
1908    }
1909
1910    public void TestFieldPositionInteger() {
1911        DecimalFormat nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1912        nf.setPositivePrefix("FOO");
1913        nf.setPositiveSuffix("BA");
1914        StringBuffer buffer = new StringBuffer();
1915        FieldPosition fp = new FieldPosition(NumberFormat.Field.INTEGER);
1916        nf.format(35.47, buffer, fp);
1917        assertEquals("35.47", "FOO35.47BA", buffer.toString());
1918        assertEquals("fp begin", 3, fp.getBeginIndex());
1919        assertEquals("fp end", 5, fp.getEndIndex());
1920    }
1921
1922    public void TestFieldPositionFractionButInteger() {
1923        DecimalFormat nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1924        nf.setPositivePrefix("FOO");
1925        nf.setPositiveSuffix("BA");
1926        StringBuffer buffer = new StringBuffer();
1927        FieldPosition fp = new FieldPosition(NumberFormat.Field.FRACTION);
1928        nf.format(35, buffer, fp);
1929        assertEquals("35", "FOO35BA", buffer.toString());
1930        assertEquals("fp begin", 5, fp.getBeginIndex());
1931        assertEquals("fp end", 5, fp.getEndIndex());
1932    }
1933
1934    public void TestFieldPositionFraction() {
1935        DecimalFormat nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1936        nf.setPositivePrefix("FOO");
1937        nf.setPositiveSuffix("BA");
1938        StringBuffer buffer = new StringBuffer();
1939        FieldPosition fp = new FieldPosition(NumberFormat.Field.FRACTION);
1940        nf.format(35.47, buffer, fp);
1941        assertEquals("35.47", "FOO35.47BA", buffer.toString());
1942        assertEquals("fp begin", 6, fp.getBeginIndex());
1943        assertEquals("fp end", 8, fp.getEndIndex());
1944    }
1945
1946    public void TestRounding() {
1947        DecimalFormat nf = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1948        if (false) { // for debugging specific value
1949            nf.setRoundingMode(BigDecimal.ROUND_HALF_UP);
1950            checkRounding(nf, new BigDecimal("300.0300000000"), 0, new BigDecimal("0.020000000"));
1951        }
1952        // full tests
1953        int[] roundingIncrements = {1, 2, 5, 20, 50, 100};
1954        int[] testValues = {0, 300};
1955        for (int j = 0; j < testValues.length; ++j) {
1956            for (int mode = BigDecimal.ROUND_UP; mode < BigDecimal.ROUND_HALF_EVEN; ++mode) {
1957                nf.setRoundingMode(mode);
1958                for (int increment = 0; increment < roundingIncrements.length; ++increment) {
1959                    BigDecimal base = new BigDecimal(testValues[j]);
1960                    BigDecimal rInc = new BigDecimal(roundingIncrements[increment]);
1961                    checkRounding(nf,  base, 20, rInc);
1962                    rInc = new BigDecimal("1.000000000").divide(rInc);
1963                    checkRounding(nf,  base, 20, rInc);
1964                }
1965            }
1966        }
1967    }
1968
1969    public void TestRoundingPattern() {
1970        class TestRoundingPatternItem {
1971            String     pattern;
1972            double     roundingIncrement;
1973            double     testCase;
1974            String     expected;
1975
1976            TestRoundingPatternItem(String pattern, double roundingIncrement, double testCase, String expected) {
1977                this.pattern = pattern;
1978                this.roundingIncrement = roundingIncrement;
1979                this.testCase = testCase;
1980                this.expected = expected;
1981            }
1982        };
1983
1984        TestRoundingPatternItem []tests = {
1985                new TestRoundingPatternItem("##0.65", 0.65, 1.234, "1.30"),
1986                new TestRoundingPatternItem("#50", 50.0, 1230, "1250")
1987        };
1988
1989        DecimalFormat df = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1990        String result;
1991        BigDecimal bd;
1992        for (int i = 0; i < tests.length; i++) {
1993            df.applyPattern(tests[i].pattern);
1994
1995            result = df.format(tests[i].testCase);
1996
1997            if (!tests[i].expected.equals(result)) {
1998                errln("String Pattern Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
1999            }
2000
2001            bd = new BigDecimal(tests[i].roundingIncrement);
2002
2003            df.setRoundingIncrement(bd);
2004
2005            result = df.format(tests[i].testCase);
2006
2007            if (!tests[i].expected.equals(result)) {
2008                errln("BigDecimal Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
2009            }
2010        }
2011    }
2012
2013    public void TestBigDecimalRounding() {
2014        String figure = "50.000000004";
2015        Double dbl = new Double(figure);
2016        BigDecimal dec = new BigDecimal(figure);
2017
2018        DecimalFormat f = (DecimalFormat) NumberFormat.getInstance();
2019        f.applyPattern("00.00######");
2020
2021        assertEquals("double format", "50.00", f.format(dbl));
2022        assertEquals("bigdec format", "50.00", f.format(dec));
2023
2024        int maxFracDigits = f.getMaximumFractionDigits();
2025        BigDecimal roundingIncrement = new BigDecimal("1").movePointLeft(maxFracDigits);
2026
2027        f.setRoundingIncrement(roundingIncrement);
2028        f.setRoundingMode(BigDecimal.ROUND_DOWN);
2029        assertEquals("Rounding down", f.format(dbl), f.format(dec));
2030
2031        f.setRoundingIncrement(roundingIncrement);
2032        f.setRoundingMode(BigDecimal.ROUND_HALF_UP);
2033        assertEquals("Rounding half up", f.format(dbl), f.format(dec));
2034    }
2035
2036    void checkRounding(DecimalFormat nf, BigDecimal base, int iterations, BigDecimal increment) {
2037        nf.setRoundingIncrement(increment.toBigDecimal());
2038        BigDecimal lastParsed = new BigDecimal(Integer.MIN_VALUE); // used to make sure that rounding is monotonic
2039        for (int i = -iterations; i <= iterations; ++i) {
2040            BigDecimal iValue = base.add(increment.multiply(new BigDecimal(i)).movePointLeft(1));
2041            BigDecimal smallIncrement = new BigDecimal("0.00000001");
2042            if (iValue.signum() != 0) {
2043                smallIncrement.multiply(iValue); // scale unless zero
2044            }
2045            // we not only test the value, but some values in a small range around it.
2046            lastParsed = checkRound(nf, iValue.subtract(smallIncrement), lastParsed);
2047            lastParsed = checkRound(nf, iValue, lastParsed);
2048            lastParsed = checkRound(nf, iValue.add(smallIncrement), lastParsed);
2049        }
2050    }
2051
2052    private BigDecimal checkRound(DecimalFormat nf, BigDecimal iValue, BigDecimal lastParsed) {
2053        String formatedBigDecimal = nf.format(iValue);
2054        String formattedDouble = nf.format(iValue.doubleValue());
2055        if (!equalButForTrailingZeros(formatedBigDecimal, formattedDouble)) {
2056
2057            errln("Failure at: " + iValue + " (" + iValue.doubleValue() + ")"
2058                    + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
2059                            + ",\tRounding-increment: " + nf.getRoundingIncrement()
2060                            + ",\tdouble: " + formattedDouble
2061                            + ",\tBigDecimal: " + formatedBigDecimal);
2062
2063        } else {
2064            logln("Value: " + iValue
2065                    + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
2066                            + ",\tRounding-increment: " + nf.getRoundingIncrement()
2067                            + ",\tdouble: " + formattedDouble
2068                            + ",\tBigDecimal: " + formatedBigDecimal);
2069        }
2070        try {
2071            // Number should have compareTo(...)
2072            BigDecimal parsed = toBigDecimal(nf.parse(formatedBigDecimal));
2073            if (lastParsed.compareTo(parsed) > 0) {
2074                errln("Rounding wrong direction!: " + lastParsed + " > " + parsed);
2075            }
2076            lastParsed = parsed;
2077        } catch (ParseException e) {
2078            errln("Parse Failure with: " + formatedBigDecimal);
2079        }
2080        return lastParsed;
2081    }
2082
2083    static BigDecimal toBigDecimal(Number number) {
2084        return number instanceof BigDecimal ? (BigDecimal) number
2085                : number instanceof BigInteger ? new BigDecimal((BigInteger)number)
2086        : number instanceof java.math.BigDecimal ? new BigDecimal((java.math.BigDecimal)number)
2087                : number instanceof Double ? new BigDecimal(number.doubleValue())
2088        : number instanceof Float ? new BigDecimal(number.floatValue())
2089                : new BigDecimal(number.longValue());
2090    }
2091
2092    static String[] roundingModeNames = {
2093        "ROUND_UP", "ROUND_DOWN", "ROUND_CEILING", "ROUND_FLOOR",
2094        "ROUND_HALF_UP", "ROUND_HALF_DOWN", "ROUND_HALF_EVEN",
2095        "ROUND_UNNECESSARY"
2096    };
2097
2098    private static boolean equalButForTrailingZeros(String formatted1, String formatted2) {
2099        if (formatted1.length() == formatted2.length()) return formatted1.equals(formatted2);
2100        return stripFinalZeros(formatted1).equals(stripFinalZeros(formatted2));
2101    }
2102
2103    private static String stripFinalZeros(String formatted) {
2104        int len1 = formatted.length();
2105        char ch;
2106        while (len1 > 0 && ((ch = formatted.charAt(len1-1)) == '0' || ch == '.')) --len1;
2107        if (len1==1 && ((ch = formatted.charAt(len1-1)) == '-')) --len1;
2108        return formatted.substring(0,len1);
2109    }
2110
2111    //------------------------------------------------------------------
2112    // Support methods
2113    //------------------------------------------------------------------
2114
2115    // Format-Parse test
2116    public void expect2(NumberFormat fmt, Number n, String exp) {
2117        // Don't round-trip format test, since we explicitly do it
2118        expect(fmt, n, exp, false);
2119        expect(fmt, exp, n);
2120    }
2121    // Format-Parse test
2122    public void expect3(NumberFormat fmt, Number n, String exp) {
2123        // Don't round-trip format test, since we explicitly do it
2124        expect_rbnf(fmt, n, exp, false);
2125        expect_rbnf(fmt, exp, n);
2126    }
2127
2128    // Format-Parse test (convenience)
2129    public void expect2(NumberFormat fmt, double n, String exp) {
2130        expect2(fmt, new Double(n), exp);
2131    }
2132    // Format-Parse test (convenience)
2133    public void expect3(NumberFormat fmt, double n, String exp) {
2134        expect3(fmt, new Double(n), exp);
2135    }
2136
2137    // Format-Parse test (convenience)
2138    public void expect2(NumberFormat fmt, long n, String exp) {
2139        expect2(fmt, new Long(n), exp);
2140    }
2141    // Format-Parse test (convenience)
2142    public void expect3(NumberFormat fmt, long n, String exp) {
2143        expect3(fmt, new Long(n), exp);
2144    }
2145
2146    // Format test
2147    public void expect(NumberFormat fmt, Number n, String exp, boolean rt) {
2148        StringBuffer saw = new StringBuffer();
2149        FieldPosition pos = new FieldPosition(0);
2150        fmt.format(n, saw, pos);
2151        String pat = ((DecimalFormat)fmt).toPattern();
2152        if (saw.toString().equals(exp)) {
2153            logln("Ok   " + n + " x " +
2154                    pat + " = \"" +
2155                    saw + "\"");
2156            // We should be able to round-trip the formatted string =>
2157            // number => string (but not the other way around: number
2158            // => string => number2, might have number2 != number):
2159            if (rt) {
2160                try {
2161                    Number n2 = fmt.parse(exp);
2162                    StringBuffer saw2 = new StringBuffer();
2163                    fmt.format(n2, saw2, pos);
2164                    if (!saw2.toString().equals(exp)) {
2165                        errln("expect() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2166                                ", FAIL \"" + exp + "\" => " + n2 + " => \"" + saw2 + '"');
2167                    }
2168                } catch (ParseException e) {
2169                    errln("expect() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2170                            ", " + e.getMessage());
2171                    return;
2172                }
2173            }
2174        } else {
2175            errln("expect() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2176                    ", FAIL " + n + " x " + pat + " = \"" + saw + "\", expected \"" + exp + "\"");
2177        }
2178    }
2179    // Format test
2180    public void expect_rbnf(NumberFormat fmt, Number n, String exp, boolean rt) {
2181        StringBuffer saw = new StringBuffer();
2182        FieldPosition pos = new FieldPosition(0);
2183        fmt.format(n, saw, pos);
2184        if (saw.toString().equals(exp)) {
2185            logln("Ok   " + n + " = \"" +
2186                    saw + "\"");
2187            // We should be able to round-trip the formatted string =>
2188            // number => string (but not the other way around: number
2189            // => string => number2, might have number2 != number):
2190            if (rt) {
2191                try {
2192                    Number n2 = fmt.parse(exp);
2193                    StringBuffer saw2 = new StringBuffer();
2194                    fmt.format(n2, saw2, pos);
2195                    if (!saw2.toString().equals(exp)) {
2196                        errln("expect_rbnf() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2197                                ", FAIL \"" + exp + "\" => " + n2 + " => \"" + saw2 + '"');
2198                    }
2199                } catch (ParseException e) {
2200                    errln("expect_rbnf() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2201                            ", " + e.getMessage());
2202                    return;
2203                }
2204            }
2205        } else {
2206            errln("expect_rbnf() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2207                    ", FAIL " + n + " = \"" + saw + "\", expected \"" + exp + "\"");
2208        }
2209    }
2210
2211    // Format test (convenience)
2212    public void expect(NumberFormat fmt, Number n, String exp) {
2213        expect(fmt, n, exp, true);
2214    }
2215
2216    // Format test (convenience)
2217    public void expect(NumberFormat fmt, double n, String exp) {
2218        expect(fmt, new Double(n), exp);
2219    }
2220
2221    // Format test (convenience)
2222    public void expect(NumberFormat fmt, long n, String exp) {
2223        expect(fmt, new Long(n), exp);
2224    }
2225
2226    // Parse test
2227    public void expect(NumberFormat fmt, String str, Number n) {
2228        Number num = null;
2229        try {
2230            num = fmt.parse(str);
2231        } catch (ParseException e) {
2232            errln(e.getMessage());
2233            return;
2234        }
2235        String pat = ((DecimalFormat)fmt).toPattern();
2236        // A little tricky here -- make sure Double(12345.0) and
2237        // Long(12345) match.
2238        if (num.equals(n) || num.doubleValue() == n.doubleValue()) {
2239            logln("Ok   \"" + str + "\" x " +
2240                    pat + " = " +
2241                    num);
2242        } else {
2243            errln("expect() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2244                    ", FAIL \"" + str + "\" x " + pat + " = " + num + ", expected " + n);
2245        }
2246    }
2247
2248    // Parse test
2249    public void expect_rbnf(NumberFormat fmt, String str, Number n) {
2250        Number num = null;
2251        try {
2252            num = fmt.parse(str);
2253        } catch (ParseException e) {
2254            errln(e.getMessage());
2255            return;
2256        }
2257        // A little tricky here -- make sure Double(12345.0) and
2258        // Long(12345) match.
2259        if (num.equals(n) || num.doubleValue() == n.doubleValue()) {
2260            logln("Ok   \"" + str + " = " +
2261                    num);
2262        } else {
2263            errln("expect_rbnf() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2264                    ", FAIL \"" + str + " = " + num + ", expected " + n);
2265        }
2266    }
2267
2268    // Parse test (convenience)
2269    public void expect(NumberFormat fmt, String str, double n) {
2270        expect(fmt, str, new Double(n));
2271    }
2272
2273    // Parse test (convenience)
2274    public void expect(NumberFormat fmt, String str, long n) {
2275        expect(fmt, str, new Long(n));
2276    }
2277
2278    private void expectCurrency(NumberFormat nf, Currency curr,
2279            double value, String string) {
2280        DecimalFormat fmt = (DecimalFormat) nf;
2281        if (curr != null) {
2282            fmt.setCurrency(curr);
2283        }
2284        String s = fmt.format(value).replace('\u00A0', ' ');
2285
2286        if (s.equals(string)) {
2287            logln("Ok: " + value + " x " + curr + " => " + s);
2288        } else {
2289            errln("FAIL: " + value + " x " + curr + " => " + s +
2290                    ", expected " + string);
2291        }
2292    }
2293
2294    public void expectPad(DecimalFormat fmt, String pat, int pos) {
2295        expectPad(fmt, pat, pos, 0, (char)0);
2296    }
2297
2298    public void expectPad(DecimalFormat fmt, final String pat, int pos, int width, final char pad) {
2299        int apos = 0, awidth = 0;
2300        char apadStr;
2301        try {
2302            fmt.applyPattern(pat);
2303            apos = fmt.getPadPosition();
2304            awidth = fmt.getFormatWidth();
2305            apadStr = fmt.getPadCharacter();
2306        } catch (Exception e) {
2307            apos = -1;
2308            awidth = width;
2309            apadStr = pad;
2310        }
2311
2312        if (apos == pos && awidth == width && apadStr == pad) {
2313            logln("Ok   \"" + pat + "\" pos="
2314                    + apos + ((pos == -1) ? "" : " width=" + awidth + " pad=" + apadStr));
2315        } else {
2316            errln("FAIL \"" + pat + "\" pos=" + apos + " width="
2317                    + awidth + " pad=" + apadStr + ", expected "
2318                    + pos + " " + width + " " + pad);
2319        }
2320    }
2321
2322    public void expectPat(DecimalFormat fmt, final String exp) {
2323        String pat = fmt.toPattern();
2324        if (pat.equals(exp)) {
2325            logln("Ok   \"" + pat + "\"");
2326        } else {
2327            errln("FAIL \"" + pat + "\", expected \"" + exp + "\"");
2328        }
2329    }
2330
2331
2332    private void expectParseCurrency(NumberFormat fmt, Currency expected, String text) {
2333        ParsePosition pos = new ParsePosition(0);
2334        CurrencyAmount currencyAmount = fmt.parseCurrency(text, pos);
2335        assertTrue("Parse of " + text + " should have succeeded.", pos.getIndex() > 0);
2336        assertEquals("Currency should be correct.", expected, currencyAmount.getCurrency());
2337    }
2338
2339    public void TestJB3832(){
2340        ULocale locale = new ULocale("pt_PT@currency=PTE");
2341        NumberFormat format = NumberFormat.getCurrencyInstance(locale);
2342        Currency curr = Currency.getInstance(locale);
2343        logln("\nName of the currency is: " + curr.getName(locale, Currency.LONG_NAME, new boolean[] {false}));
2344        CurrencyAmount cAmt = new CurrencyAmount(1150.50, curr);
2345        logln("CurrencyAmount object's hashCode is: " + cAmt.hashCode()); //cover hashCode
2346        String str = format.format(cAmt);
2347        String expected = "1,150$50\u00a0\u200b";
2348        if(!expected.equals(str)){
2349            errln("Did not get the expected output Expected: "+expected+" Got: "+ str);
2350        }
2351    }
2352
2353    public void TestStrictParse() {
2354        String[] pass = {
2355                "0",           // single zero before end of text is not leading
2356                "0 ",          // single zero at end of number is not leading
2357                "0.",          // single zero before period (or decimal, it's ambiguous) is not leading
2358                "0,",          // single zero before comma (not group separator) is not leading
2359                "0.0",         // single zero before decimal followed by digit is not leading
2360                "0. ",         // same as above before period (or decimal) is not leading
2361                "0.100,5",     // comma stops parse of decimal (no grouping)
2362                ".00",         // leading decimal is ok, even with zeros
2363                "1234567",     // group separators are not required
2364                "12345, ",     // comma not followed by digit is not a group separator, but end of number
2365                "1,234, ",     // if group separator is present, group sizes must be appropriate
2366                "1,234,567",   // ...secondary too
2367                "0E",          // an exponent not followed by zero or digits is not an exponent
2368                "00",          // leading zero before zero - used to be error - see ticket #7913
2369                "012",         // leading zero before digit - used to be error - see ticket #7913
2370                "0,456",       // leading zero before group separator - used to be error - see ticket #7913
2371        };
2372        String[] fail = {
2373                "1,2",       // wrong number of digits after group separator
2374                ",0",        // leading group separator before zero
2375                ",1",        // leading group separator before digit
2376                ",.02",      // leading group separator before decimal
2377                "1,.02",     // group separator before decimal
2378                "1,,200",    // multiple group separators
2379                "1,45",      // wrong number of digits in primary group
2380                "1,45 that", // wrong number of digits in primary group
2381                "1,45.34",   // wrong number of digits in primary group
2382                "1234,567",  // wrong number of digits in secondary group
2383                "12,34,567", // wrong number of digits in secondary group
2384                "1,23,456,7890", // wrong number of digits in primary and secondary groups
2385        };
2386
2387        DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
2388        runStrictParseBatch(nf, pass, fail);
2389
2390        String[] scientificPass = {
2391                "0E2",      // single zero before exponent is ok
2392                "1234E2",   // any number of digits before exponent is ok
2393                "1,234E",   // an exponent string not followed by zero or digits is not an exponent
2394                "00E2",     // leading zeroes now allowed in strict mode - see ticket #
2395        };
2396        String[] scientificFail = {
2397                "1,234E2",  // group separators with exponent fail
2398        };
2399
2400        nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
2401        runStrictParseBatch(nf, scientificPass, scientificFail);
2402
2403        String[] mixedPass = {
2404                "12,34,567",
2405                "12,34,567,",
2406                "12,34,567, that",
2407                "12,34,567 that",
2408        };
2409        String[] mixedFail = {
2410                "12,34,56",
2411                "12,34,56,",
2412                "12,34,56, that ",
2413                "12,34,56 that",
2414        };
2415
2416        nf = new DecimalFormat("#,##,##0.#");
2417        runStrictParseBatch(nf, mixedPass, mixedFail);
2418    }
2419
2420    void runStrictParseBatch(DecimalFormat nf, String[] pass, String[] fail) {
2421        nf.setParseStrict(false);
2422        runStrictParseTests("should pass", nf, pass, true);
2423        runStrictParseTests("should also pass", nf, fail, true);
2424        nf.setParseStrict(true);
2425        runStrictParseTests("should still pass", nf, pass, true);
2426        runStrictParseTests("should fail", nf, fail, false);
2427    }
2428
2429    void runStrictParseTests(String msg, DecimalFormat nf, String[] tests, boolean pass) {
2430        logln("");
2431        logln("pattern: '" + nf.toPattern() + "'");
2432        logln(msg);
2433        for (int i = 0; i < tests.length; ++i) {
2434            String str = tests[i];
2435            ParsePosition pp = new ParsePosition(0);
2436            Number n = nf.parse(str, pp);
2437            String formatted = n != null ? nf.format(n) : "null";
2438            String err = pp.getErrorIndex() == -1 ? "" : "(error at " + pp.getErrorIndex() + ")";
2439            if ((err.length() == 0) != pass) {
2440                errln("'" + str + "' parsed '" +
2441                        str.substring(0, pp.getIndex()) +
2442                        "' returned " + n + " formats to '" +
2443                        formatted + "' " + err);
2444            } else {
2445                if (err.length() > 0) {
2446                    err = "got expected " + err;
2447                }
2448                logln("'" + str + "' parsed '" +
2449                        str.substring(0, pp.getIndex()) +
2450                        "' returned " + n + " formats to '" +
2451                        formatted + "' " + err);
2452            }
2453        }
2454    }
2455    public void TestJB5251(){
2456        //save default locale
2457        ULocale defaultLocale = ULocale.getDefault();
2458        ULocale.setDefault(new ULocale("qr_QR"));
2459        try {
2460            NumberFormat.getInstance();
2461        }
2462        catch (Exception e) {
2463            errln("Numberformat threw exception for non-existent locale. It should use the default.");
2464        }
2465        //reset default locale
2466        ULocale.setDefault(defaultLocale);
2467    }
2468
2469    public void TestParseReturnType() {
2470        String[] defaultNonBigDecimals = {
2471                "123",      // Long
2472                "123.0",    // Long
2473                "0.0",      // Long
2474                "12345678901234567890"      // BigInteger
2475        };
2476
2477        String[] doubles = {
2478                "-0.0",
2479                "NaN",
2480                "\u221E"    // Infinity
2481        };
2482
2483        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
2484        DecimalFormat nf = new DecimalFormat("#.#", sym);
2485
2486        if (nf.isParseBigDecimal()) {
2487            errln("FAIL: isParseDecimal() must return false by default");
2488        }
2489
2490        // isParseBigDecimal() is false
2491        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
2492            try {
2493                Number n = nf.parse(defaultNonBigDecimals[i]);
2494                if (n instanceof BigDecimal) {
2495                    errln("FAIL: parse returns BigDecimal instance");
2496                }
2497            } catch (ParseException e) {
2498                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
2499            }
2500        }
2501        // parse results for doubls must be always Double
2502        for (int i = 0; i < doubles.length; i++) {
2503            try {
2504                Number n = nf.parse(doubles[i]);
2505                if (!(n instanceof Double)) {
2506                    errln("FAIL: parse does not return Double instance");
2507                }
2508            } catch (ParseException e) {
2509                errln("parse of '" + doubles[i] + "' threw exception: " + e);
2510            }
2511        }
2512
2513        // force this DecimalFormat to return BigDecimal
2514        nf.setParseBigDecimal(true);
2515        if (!nf.isParseBigDecimal()) {
2516            errln("FAIL: isParseBigDecimal() must return true");
2517        }
2518
2519        // isParseBigDecimal() is true
2520        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
2521            try {
2522                Number n = nf.parse(defaultNonBigDecimals[i]);
2523                if (!(n instanceof BigDecimal)) {
2524                    errln("FAIL: parse does not return BigDecimal instance");
2525                }
2526            } catch (ParseException e) {
2527                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
2528            }
2529        }
2530        // parse results for doubls must be always Double
2531        for (int i = 0; i < doubles.length; i++) {
2532            try {
2533                Number n = nf.parse(doubles[i]);
2534                if (!(n instanceof Double)) {
2535                    errln("FAIL: parse does not return Double instance");
2536                }
2537            } catch (ParseException e) {
2538                errln("parse of '" + doubles[i] + "' threw exception: " + e);
2539            }
2540        }
2541    }
2542
2543    public void TestNonpositiveMultiplier() {
2544        DecimalFormat df = new DecimalFormat("0");
2545
2546        // test zero multiplier
2547
2548        try {
2549            df.setMultiplier(0);
2550
2551            // bad
2552            errln("DecimalFormat.setMultiplier(0) did not throw an IllegalArgumentException");
2553        } catch (IllegalArgumentException ex) {
2554            // good
2555        }
2556
2557        // test negative multiplier
2558
2559        try {
2560            df.setMultiplier(-1);
2561
2562            if (df.getMultiplier() != -1) {
2563                errln("DecimalFormat.setMultiplier(-1) did not change the multiplier to -1");
2564                return;
2565            }
2566
2567            // good
2568        } catch (IllegalArgumentException ex) {
2569            // bad
2570            errln("DecimalFormat.setMultiplier(-1) threw an IllegalArgumentException");
2571            return;
2572        }
2573
2574        expect(df, "1122.123", -1122.123);
2575        expect(df, "-1122.123", 1122.123);
2576        expect(df, "1.2", -1.2);
2577        expect(df, "-1.2", 1.2);
2578
2579        expect2(df, Long.MAX_VALUE, BigInteger.valueOf(Long.MAX_VALUE).negate().toString());
2580        expect2(df, Long.MIN_VALUE, BigInteger.valueOf(Long.MIN_VALUE).negate().toString());
2581        expect2(df, Long.MAX_VALUE / 2, BigInteger.valueOf(Long.MAX_VALUE / 2).negate().toString());
2582        expect2(df, Long.MIN_VALUE / 2, BigInteger.valueOf(Long.MIN_VALUE / 2).negate().toString());
2583
2584        expect2(df, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
2585        expect2(df, BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
2586
2587        expect2(df, java.math.BigDecimal.valueOf(Long.MAX_VALUE), java.math.BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
2588        expect2(df, java.math.BigDecimal.valueOf(Long.MIN_VALUE), java.math.BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
2589    }
2590
2591    public void TestJB5358() {
2592        int numThreads = 10;
2593        String numstr = "12345";
2594        double expected = 12345;
2595        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
2596        DecimalFormat fmt = new DecimalFormat("#.#", sym);
2597        ArrayList errors = new ArrayList();
2598
2599        ParseThreadJB5358[] threads = new ParseThreadJB5358[numThreads];
2600        for (int i = 0; i < numThreads; i++) {
2601            threads[i] = new ParseThreadJB5358((DecimalFormat)fmt.clone(), numstr, expected, errors);
2602            threads[i].start();
2603        }
2604        for (int i = 0; i < numThreads; i++) {
2605            try {
2606                threads[i].join();
2607            } catch (InterruptedException ie) {
2608                ie.printStackTrace();
2609            }
2610        }
2611        if (errors.size() != 0) {
2612            StringBuffer errBuf = new StringBuffer();
2613            for (int i = 0; i < errors.size(); i++) {
2614                errBuf.append((String)errors.get(i));
2615                errBuf.append("\n");
2616            }
2617            errln("FAIL: " + errBuf);
2618        }
2619    }
2620
2621    static private class ParseThreadJB5358 extends Thread {
2622        private final DecimalFormat decfmt;
2623        private final String numstr;
2624        private final double expect;
2625        private final ArrayList errors;
2626
2627        public ParseThreadJB5358(DecimalFormat decfmt, String numstr, double expect, ArrayList errors) {
2628            this.decfmt = decfmt;
2629            this.numstr = numstr;
2630            this.expect = expect;
2631            this.errors = errors;
2632        }
2633
2634        @Override
2635        public void run() {
2636            for (int i = 0; i < 10000; i++) {
2637                try {
2638                    Number n = decfmt.parse(numstr);
2639                    if (n.doubleValue() != expect) {
2640                        synchronized(errors) {
2641                            errors.add(new String("Bad parse result - expected:" + expect + " actual:" + n.doubleValue()));
2642                        }
2643                    }
2644                } catch (Throwable t) {
2645                    synchronized(errors) {
2646                        errors.add(new String(t.getClass().getName() + " - " + t.getMessage()));
2647                    }
2648                }
2649            }
2650        }
2651    }
2652
2653    public void TestSetCurrency() {
2654        DecimalFormatSymbols decf1 = DecimalFormatSymbols.getInstance(ULocale.US);
2655        DecimalFormatSymbols decf2 = DecimalFormatSymbols.getInstance(ULocale.US);
2656        decf2.setCurrencySymbol("UKD");
2657        DecimalFormat format1 = new DecimalFormat("000.000", decf1);
2658        DecimalFormat format2 = new DecimalFormat("000.000", decf2);
2659        Currency euro = Currency.getInstance("EUR");
2660        format1.setCurrency(euro);
2661        format2.setCurrency(euro);
2662        assertEquals("Reset with currency symbol", format1, format2);
2663    }
2664
2665    /*
2666     * Testing the method public StringBuffer format(Object number, ...)
2667     */
2668    public void TestFormat() {
2669        NumberFormat nf = NumberFormat.getInstance();
2670        StringBuffer sb = new StringBuffer("dummy");
2671        FieldPosition fp = new FieldPosition(0);
2672
2673        // Tests when "if (number instanceof Long)" is true
2674        try {
2675            nf.format(new Long("0"), sb, fp);
2676        } catch (Exception e) {
2677            errln("NumberFormat.format(Object number, ...) was not suppose to "
2678                    + "return an exception for a Long object. Error: " + e);
2679        }
2680
2681        // Tests when "else if (number instanceof BigInteger)" is true
2682        try {
2683            nf.format((Object)new BigInteger("0"), sb, fp);
2684        } catch (Exception e) {
2685            errln("NumberFormat.format(Object number, ...) was not suppose to "
2686                    + "return an exception for a BigInteger object. Error: " + e);
2687        }
2688
2689        // Tests when "else if (number instanceof java.math.BigDecimal)" is true
2690        try {
2691            nf.format((Object)new java.math.BigDecimal("0"), sb, fp);
2692        } catch (Exception e) {
2693            errln("NumberFormat.format(Object number, ...) was not suppose to "
2694                    + "return an exception for a java.math.BigDecimal object. Error: " + e);
2695        }
2696
2697        // Tests when "else if (number instanceof com.ibm.icu.math.BigDecimal)" is true
2698        try {
2699            nf.format((Object)new com.ibm.icu.math.BigDecimal("0"), sb, fp);
2700        } catch (Exception e) {
2701            errln("NumberFormat.format(Object number, ...) was not suppose to "
2702                    + "return an exception for a com.ibm.icu.math.BigDecimal object. Error: " + e);
2703        }
2704
2705        // Tests when "else if (number instanceof CurrencyAmount)" is true
2706        try {
2707            CurrencyAmount ca = new CurrencyAmount(0.0, Currency.getInstance(new ULocale("en_US")));
2708            nf.format((Object)ca, sb, fp);
2709        } catch (Exception e) {
2710            errln("NumberFormat.format(Object number, ...) was not suppose to "
2711                    + "return an exception for a CurrencyAmount object. Error: " + e);
2712        }
2713
2714        // Tests when "else if (number instanceof Number)" is true
2715        try {
2716            nf.format(0.0, sb, fp);
2717        } catch (Exception e) {
2718            errln("NumberFormat.format(Object number, ...) was not suppose to "
2719                    + "to return an exception for a Number object. Error: " + e);
2720        }
2721
2722        // Tests when "else" is true
2723        try {
2724            nf.format(new Object(), sb, fp);
2725            errln("NumberFormat.format(Object number, ...) was suppose to "
2726                    + "return an exception for an invalid object.");
2727        } catch (Exception e) {
2728        }
2729
2730        try {
2731            nf.format(new String("dummy"), sb, fp);
2732            errln("NumberFormat.format(Object number, ...) was suppose to "
2733                    + "return an exception for an invalid object.");
2734        } catch (Exception e) {
2735        }
2736    }
2737
2738    /*
2739     * Tests the method public final static NumberFormat getInstance(int style) public static NumberFormat
2740     * getInstance(Locale inLocale, int style) public static NumberFormat getInstance(ULocale desiredLocale, int choice)
2741     */
2742    public void TestGetInstance() {
2743        // Tests "public final static NumberFormat getInstance(int style)"
2744        int maxStyle = NumberFormat.CASHCURRENCYSTYLE;
2745
2746        int[] invalid_cases = { NumberFormat.NUMBERSTYLE - 1, NumberFormat.NUMBERSTYLE - 2,
2747                maxStyle + 1, maxStyle + 2 };
2748
2749        for (int i = NumberFormat.NUMBERSTYLE; i < maxStyle; i++) {
2750            try {
2751                NumberFormat.getInstance(i);
2752            } catch (Exception e) {
2753                errln("NumberFormat.getInstance(int style) was not suppose to "
2754                        + "return an exception for passing value of " + i);
2755            }
2756        }
2757
2758        for (int i = 0; i < invalid_cases.length; i++) {
2759            try {
2760                NumberFormat.getInstance(invalid_cases[i]);
2761                errln("NumberFormat.getInstance(int style) was suppose to "
2762                        + "return an exception for passing value of " + invalid_cases[i]);
2763            } catch (Exception e) {
2764            }
2765        }
2766
2767        // Tests "public static NumberFormat getInstance(Locale inLocale, int style)"
2768        String[] localeCases = { "en_US", "fr_FR", "de_DE", "jp_JP" };
2769
2770        for (int i = NumberFormat.NUMBERSTYLE; i < maxStyle; i++) {
2771            for (int j = 0; j < localeCases.length; j++) {
2772                try {
2773                    NumberFormat.getInstance(new Locale(localeCases[j]), i);
2774                } catch (Exception e) {
2775                    errln("NumberFormat.getInstance(Locale inLocale, int style) was not suppose to "
2776                            + "return an exception for passing value of " + localeCases[j] + ", " + i);
2777                }
2778            }
2779        }
2780
2781        // Tests "public static NumberFormat getInstance(ULocale desiredLocale, int choice)"
2782        // Tests when "if (choice < NUMBERSTYLE || choice > PLURALCURRENCYSTYLE)" is true
2783        for (int i = 0; i < invalid_cases.length; i++) {
2784            try {
2785                NumberFormat.getInstance((ULocale) null, invalid_cases[i]);
2786                errln("NumberFormat.getInstance(ULocale inLocale, int choice) was not suppose to "
2787                        + "return an exception for passing value of " + invalid_cases[i]);
2788            } catch (Exception e) {
2789            }
2790        }
2791    }
2792
2793    /*
2794     * Tests the class public static abstract class NumberFormatFactory
2795     */
2796    public void TestNumberFormatFactory() {
2797        /*
2798         * The following class allows the method public NumberFormat createFormat(Locale loc, int formatType) to be
2799         * tested.
2800         */
2801        class TestFactory extends NumberFormatFactory {
2802            @Override
2803            public Set<String> getSupportedLocaleNames() {
2804                return null;
2805            }
2806
2807            @Override
2808            public NumberFormat createFormat(ULocale loc, int formatType) {
2809                return null;
2810            }
2811        }
2812
2813        /*
2814         * The following class allows the method public NumberFormat createFormat(ULocale loc, int formatType) to be
2815         * tested.
2816         */
2817        class TestFactory1 extends NumberFormatFactory {
2818            @Override
2819            public Set<String> getSupportedLocaleNames() {
2820                return null;
2821            }
2822
2823            @Override
2824            public NumberFormat createFormat(Locale loc, int formatType) {
2825                return null;
2826            }
2827        }
2828
2829        TestFactory tf = new TestFactory();
2830        TestFactory1 tf1 = new TestFactory1();
2831
2832        /*
2833         * Tests the method public boolean visible()
2834         */
2835        if (tf.visible() != true) {
2836            errln("NumberFormatFactor.visible() was suppose to return true.");
2837        }
2838
2839        /*
2840         * Tests the method public NumberFormat createFormat(Locale loc, int formatType)
2841         */
2842        if (tf.createFormat(new Locale(""), 0) != null) {
2843            errln("NumberFormatFactor.createFormat(Locale loc, int formatType) " + "was suppose to return null");
2844        }
2845
2846        /*
2847         * Tests the method public NumberFormat createFormat(ULocale loc, int formatType)
2848         */
2849        if (tf1.createFormat(new ULocale(""), 0) != null) {
2850            errln("NumberFormatFactor.createFormat(ULocale loc, int formatType) " + "was suppose to return null");
2851        }
2852    }
2853
2854    /*
2855     * Tests the class public static abstract class SimpleNumberFormatFactory extends NumberFormatFactory
2856     */
2857    public void TestSimpleNumberFormatFactory() {
2858        class TestSimpleNumberFormatFactory extends SimpleNumberFormatFactory {
2859            /*
2860             * Tests the method public SimpleNumberFormatFactory(Locale locale)
2861             */
2862            TestSimpleNumberFormatFactory() {
2863                super(new Locale(""));
2864            }
2865        }
2866        @SuppressWarnings("unused")
2867        TestSimpleNumberFormatFactory tsnff = new TestSimpleNumberFormatFactory();
2868    }
2869
2870    /*
2871     * Tests the method public static ULocale[] getAvailableLocales()
2872     */
2873    @SuppressWarnings("static-access")
2874    public void TestGetAvailableLocales() {
2875        // Tests when "if (shim == null)" is true
2876        @SuppressWarnings("serial")
2877        class TestGetAvailableLocales extends NumberFormat {
2878            @Override
2879            public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
2880                return null;
2881            }
2882
2883            @Override
2884            public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
2885                return null;
2886            }
2887
2888            @Override
2889            public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
2890                return null;
2891            }
2892
2893            @Override
2894            public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2895                return null;
2896            }
2897
2898            @Override
2899            public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2900                return null;
2901            }
2902
2903            @Override
2904            public Number parse(String text, ParsePosition parsePosition) {
2905                return null;
2906            }
2907        }
2908
2909        try {
2910            TestGetAvailableLocales test = new TestGetAvailableLocales();
2911            test.getAvailableLocales();
2912        } catch (Exception e) {
2913            errln("NumberFormat.getAvailableLocales() was not suppose to "
2914                    + "return an exception when getting getting available locales.");
2915        }
2916    }
2917
2918    /*
2919     * Tests the method public void setMinimumIntegerDigits(int newValue)
2920     */
2921    public void TestSetMinimumIntegerDigits() {
2922        NumberFormat nf = NumberFormat.getInstance();
2923        // For valid array, it is displayed as {min value, max value}
2924        // Tests when "if (minimumIntegerDigits > maximumIntegerDigits)" is true
2925        int[][] cases = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 2, 0 }, { 2, 1 }, { 10, 0 } };
2926        int[] expectedMax = { 0, 1, 1, 2, 2, 10 };
2927        if (cases.length != expectedMax.length) {
2928            errln("Can't continue test case method TestSetMinimumIntegerDigits "
2929                    + "since the test case arrays are unequal.");
2930        } else {
2931            for (int i = 0; i < cases.length; i++) {
2932                nf.setMaximumIntegerDigits(cases[i][1]);
2933                nf.setMinimumIntegerDigits(cases[i][0]);
2934                if (nf.getMaximumIntegerDigits() != expectedMax[i]) {
2935                    errln("NumberFormat.setMinimumIntegerDigits(int newValue "
2936                            + "did not return an expected result for parameter " + cases[i][1] + " and " + cases[i][0]
2937                                    + " and expected " + expectedMax[i] + " but got " + nf.getMaximumIntegerDigits());
2938                }
2939            }
2940        }
2941    }
2942
2943    /*
2944     * Tests the method public int getRoundingMode() public void setRoundingMode(int roundingMode)
2945     */
2946    public void TestRoundingMode() {
2947        @SuppressWarnings("serial")
2948        class TestRoundingMode extends NumberFormat {
2949            @Override
2950            public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
2951                return null;
2952            }
2953
2954            @Override
2955            public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
2956                return null;
2957            }
2958
2959            @Override
2960            public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
2961                return null;
2962            }
2963
2964            @Override
2965            public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2966                return null;
2967            }
2968
2969            @Override
2970            public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2971                return null;
2972            }
2973
2974            @Override
2975            public Number parse(String text, ParsePosition parsePosition) {
2976                return null;
2977            }
2978        }
2979        TestRoundingMode tgrm = new TestRoundingMode();
2980
2981        // Tests the function 'public void setRoundingMode(int roundingMode)'
2982        try {
2983            tgrm.setRoundingMode(0);
2984            errln("NumberFormat.setRoundingMode(int) was suppose to return an exception");
2985        } catch (Exception e) {
2986        }
2987
2988        // Tests the function 'public int getRoundingMode()'
2989        try {
2990            tgrm.getRoundingMode();
2991            errln("NumberFormat.getRoundingMode() was suppose to return an exception");
2992        } catch (Exception e) {
2993        }
2994    }
2995
2996    /*
2997     * Testing lenient decimal/grouping separator parsing
2998     */
2999    public void TestLenientSymbolParsing() {
3000        DecimalFormat fmt = new DecimalFormat();
3001        DecimalFormatSymbols sym = new DecimalFormatSymbols();
3002
3003        expect(fmt, "12\u300234", 12.34);
3004
3005        // Ticket#7345 - case 1
3006        // Even strict parsing, the decimal separator set in the symbols
3007        // should be successfully parsed.
3008
3009        sym.setDecimalSeparator('\u3002');
3010
3011        // non-strict
3012        fmt.setDecimalFormatSymbols(sym);
3013
3014        // strict - failed before the fix for #7345
3015        fmt.setParseStrict(true);
3016        expect(fmt, "23\u300245", 23.45);
3017        fmt.setParseStrict(false);
3018
3019
3020        // Ticket#7345 - case 2
3021        // Decimal separator variants other than DecimalFormatSymbols.decimalSeparator
3022        // should not hide the grouping separator DecimalFormatSymbols.groupingSeparator.
3023        sym.setDecimalSeparator('.');
3024        sym.setGroupingSeparator(',');
3025        fmt.setDecimalFormatSymbols(sym);
3026
3027        expect(fmt, "1,234.56", 1234.56);
3028
3029        sym.setGroupingSeparator('\uFF61');
3030        fmt.setDecimalFormatSymbols(sym);
3031
3032        expect(fmt, "2\uFF61345.67", 2345.67);
3033
3034        // Ticket#7128
3035        //
3036        sym.setGroupingSeparator(',');
3037        fmt.setDecimalFormatSymbols(sym);
3038
3039        String skipExtSepParse = ICUConfig.get("com.ibm.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false");
3040        if (skipExtSepParse.equals("true")) {
3041            // When the property SkipExtendedSeparatorParsing is true,
3042            // DecimalFormat does not use the extended equivalent separator
3043            // data and only uses the one in DecimalFormatSymbols.
3044            expect(fmt, "23 456", 23);
3045        } else {
3046            // Lenient separator parsing is enabled by default.
3047            // A space character below is interpreted as a
3048            // group separator, even ',' is used as grouping
3049            // separator in the symbols.
3050            expect(fmt, "12 345", 12345);
3051        }
3052    }
3053
3054    /*
3055     * Testing currency driven max/min fraction digits problem
3056     * reported by ticket#7282
3057     */
3058    public void TestCurrencyFractionDigits() {
3059        double value = 99.12345;
3060
3061        // Create currency instance
3062        NumberFormat cfmt  = NumberFormat.getCurrencyInstance(new ULocale("ja_JP"));
3063        String text1 = cfmt.format(value);
3064
3065        // Reset the same currency and format the test value again
3066        cfmt.setCurrency(cfmt.getCurrency());
3067        String text2 = cfmt.format(value);
3068
3069        // output1 and output2 must be identical
3070        if (!text1.equals(text2)) {
3071            errln("NumberFormat.format() should return the same result - text1="
3072                    + text1 + " text2=" + text2);
3073        }
3074    }
3075
3076    /*
3077     * Testing rounding to negative zero problem
3078     * reported by ticket#7609
3079     */
3080    public void TestNegZeroRounding() {
3081
3082        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
3083        df.setRoundingMode(MathContext.ROUND_HALF_UP);
3084        df.setMinimumFractionDigits(1);
3085        df.setMaximumFractionDigits(1);
3086        String text1 = df.format(-0.01);
3087
3088        df.setRoundingIncrement(0.1);
3089        String text2 = df.format(-0.01);
3090
3091        // output1 and output2 must be identical
3092        if (!text1.equals(text2)) {
3093            errln("NumberFormat.format() should return the same result - text1="
3094                    + text1 + " text2=" + text2);
3095        }
3096
3097    }
3098
3099    public void TestCurrencyAmountCoverage() {
3100        CurrencyAmount ca, cb;
3101
3102        try {
3103            ca = new CurrencyAmount(null, null);
3104            errln("NullPointerException should have been thrown.");
3105        } catch (NullPointerException ex) {
3106        }
3107        try {
3108            ca = new CurrencyAmount(new Integer(0), null);
3109            errln("NullPointerException should have been thrown.");
3110        } catch (NullPointerException ex) {
3111        }
3112
3113        ca = new CurrencyAmount(new Integer(0), Currency.getInstance(new ULocale("ja_JP")));
3114        cb = new CurrencyAmount(new Integer(1), Currency.getInstance(new ULocale("ja_JP")));
3115        if (ca.equals(null)) {
3116            errln("Comparison should return false.");
3117        }
3118        if (!ca.equals(ca)) {
3119            errln("Comparision should return true.");
3120        }
3121        if (ca.equals(cb)) {
3122            errln("Comparison should return false.");
3123        }
3124    }
3125
3126    public void TestExponentParse() {
3127        ParsePosition parsePos = new ParsePosition(0);
3128        DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
3129        DecimalFormat fmt = new DecimalFormat("#####", symbols);
3130        Number result = fmt.parse("5.06e-27", parsePos);
3131        if ( result.doubleValue() != 5.06E-27 || parsePos.getIndex() != 8) {
3132            errln("ERROR: ERROR: parse failed - expected 5.06E-27, 8; got " + result.doubleValue() + ", " + parsePos.getIndex());
3133        }
3134    }
3135
3136    public void TestExplicitParents() {
3137        // We use these for testing because decimal and grouping separators will be inherited from es_419
3138        // starting with CLDR 2.0
3139        String[] DATA = {
3140                "es", "CO", "", "1.250,75",
3141                "es", "CR", "", "1.250,75",
3142                "es", "ES", "", "1.250,75",
3143                "es", "GQ", "", "1.250,75",
3144                "es", "MX", "", "1,250.75",
3145                "es", "US", "", "1,250.75",
3146                "es", "VE", "", "1.250,75",
3147
3148        };
3149
3150        for (int i=0; i<DATA.length; i+=4) {
3151            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
3152            NumberFormat fmt = NumberFormat.getInstance(locale);
3153            String s = fmt.format(1250.75);
3154            if (s.equals(DATA[i+3])) {
3155                logln("Ok: 1250.75 x " + locale + " => " + s);
3156            } else {
3157                errln("FAIL: 1250.75 x " + locale + " => " + s +
3158                        ", expected " + DATA[i+3]);
3159            }
3160        }
3161    }
3162
3163    /*
3164     * Test case for #9240
3165     * ICU4J 49.1 DecimalFormat did not clone the internal object holding
3166     * formatted text attribute information properly. Therefore, DecimalFormat
3167     * created by cloning may return incorrect results or may throw an exception
3168     * when formatToCharacterIterator is invoked from multiple threads.
3169     */
3170    public void TestFormatToCharacterIteratorThread() {
3171        final int COUNT = 10;
3172
3173        DecimalFormat fmt1 = new DecimalFormat("#0");
3174        DecimalFormat fmt2 = (DecimalFormat)fmt1.clone();
3175
3176        int[] res1 = new int[COUNT];
3177        int[] res2 = new int[COUNT];
3178
3179        Thread t1 = new Thread(new FormatCharItrTestThread(fmt1, 1, res1));
3180        Thread t2 = new Thread(new FormatCharItrTestThread(fmt2, 100, res2));
3181
3182        t1.start();
3183        t2.start();
3184
3185        try {
3186            t1.join();
3187            t2.join();
3188        } catch (InterruptedException e) {
3189            //TODO
3190        }
3191
3192        int val1 = res1[0];
3193        int val2 = res2[0];
3194
3195        for (int i = 0; i < COUNT; i++) {
3196            if (res1[i] != val1) {
3197                errln("Inconsistent first run limit in test thread 1");
3198            }
3199            if (res2[i] != val2) {
3200                errln("Inconsistent first run limit in test thread 2");
3201            }
3202        }
3203    }
3204
3205    public void TestParseMaxDigits() {
3206        DecimalFormat fmt = new DecimalFormat();
3207        String number = "100000000000";
3208        int newParseMax = number.length() - 1;
3209
3210        fmt.setParseMaxDigits(-1);
3211
3212        /* Default value is 1000 */
3213        if (fmt.getParseMaxDigits() != 1000) {
3214            errln("Fail valid value checking in setParseMaxDigits.");
3215        }
3216
3217        try {
3218            if (fmt.parse(number).doubleValue() == Float.POSITIVE_INFINITY) {
3219                errln("Got Infinity but should NOT when parsing number: " + number);
3220            }
3221
3222            fmt.setParseMaxDigits(newParseMax);
3223
3224            if (fmt.parse(number).doubleValue() != Float.POSITIVE_INFINITY) {
3225                errln("Did not get Infinity but should when parsing number: " + number);
3226            }
3227        } catch (ParseException ex) {
3228
3229        }
3230    }
3231
3232    private static class FormatCharItrTestThread implements Runnable {
3233        private final NumberFormat fmt;
3234        private final int num;
3235        private final int[] result;
3236
3237        FormatCharItrTestThread(NumberFormat fmt, int num, int[] result) {
3238            this.fmt = fmt;
3239            this.num = num;
3240            this.result = result;
3241        }
3242
3243        public void run() {
3244            for (int i = 0; i < result.length; i++) {
3245                AttributedCharacterIterator acitr = fmt.formatToCharacterIterator(num);
3246                acitr.first();
3247                result[i] = acitr.getRunLimit();
3248            }
3249        }
3250    }
3251
3252    public void TestRoundingBehavior() {
3253        final Object[][] TEST_CASES = {
3254                {
3255                    ULocale.US,                             // ULocale - null for default locale
3256                    "#.##",                                 // Pattern
3257                    Integer.valueOf(BigDecimal.ROUND_DOWN), // Rounding Mode or null (implicit)
3258                    Double.valueOf(0.0d),                   // Rounding increment, Double or BigDecimal, or null (implicit)
3259                    Double.valueOf(123.4567d),              // Input value, Long, Double, BigInteger or BigDecimal
3260                    "123.45"                                // Expected result, null for exception
3261                },
3262                {
3263                    ULocale.US,
3264                    "#.##",
3265                    null,
3266                    Double.valueOf(0.1d),
3267                    Double.valueOf(123.4567d),
3268                    "123.5"
3269                },
3270                {
3271                    ULocale.US,
3272                    "#.##",
3273                    Integer.valueOf(BigDecimal.ROUND_DOWN),
3274                    Double.valueOf(0.1d),
3275                    Double.valueOf(123.4567d),
3276                    "123.4"
3277                },
3278                {
3279                    ULocale.US,
3280                    "#.##",
3281                    Integer.valueOf(BigDecimal.ROUND_UNNECESSARY),
3282                    null,
3283                    Double.valueOf(123.4567d),
3284                    null
3285                },
3286                {
3287                    ULocale.US,
3288                    "#.##",
3289                    Integer.valueOf(BigDecimal.ROUND_DOWN),
3290                    null,
3291                    Long.valueOf(1234),
3292                    "1234"
3293                },
3294        };
3295
3296        int testNum = 1;
3297
3298        for (Object[] testCase : TEST_CASES) {
3299            // 0: locale
3300            // 1: pattern
3301            ULocale locale = testCase[0] == null ? ULocale.getDefault() : (ULocale)testCase[0];
3302            String pattern = (String)testCase[1];
3303
3304            DecimalFormat fmt = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(locale));
3305
3306            // 2: rounding mode
3307            Integer roundingMode = null;
3308            if (testCase[2] != null) {
3309                roundingMode = (Integer)testCase[2];
3310                fmt.setRoundingMode(roundingMode);
3311            }
3312
3313            // 3: rounding increment
3314            if (testCase[3] != null) {
3315                if (testCase[3] instanceof Double) {
3316                    fmt.setRoundingIncrement((Double)testCase[3]);
3317                } else if (testCase[3] instanceof BigDecimal) {
3318                    fmt.setRoundingIncrement((BigDecimal)testCase[3]);
3319                } else if (testCase[3] instanceof java.math.BigDecimal) {
3320                    fmt.setRoundingIncrement((java.math.BigDecimal)testCase[3]);
3321                }
3322            }
3323
3324            // 4: input number
3325            String s = null;
3326            boolean bException = false;
3327            try {
3328                s = fmt.format(testCase[4]);
3329            } catch (ArithmeticException e) {
3330                bException = true;
3331            }
3332
3333            if (bException) {
3334                if (testCase[5] != null) {
3335                    errln("Test case #" + testNum + ": ArithmeticException was thrown.");
3336                }
3337            } else {
3338                if (testCase[5] == null) {
3339                    errln("Test case #" + testNum +
3340                            ": ArithmeticException must be thrown, but got formatted result: " +
3341                            s);
3342                } else {
3343                    assertEquals("Test case #" + testNum, (String)testCase[5], s);
3344                }
3345            }
3346
3347            testNum++;
3348        }
3349    }
3350
3351    public void TestSignificantDigits() {
3352        double input[] = {
3353                0, 0,
3354                123, -123,
3355                12345, -12345,
3356                123.45, -123.45,
3357                123.44501, -123.44501,
3358                0.001234, -0.001234,
3359                0.00000000123, -0.00000000123,
3360                0.0000000000000000000123, -0.0000000000000000000123,
3361                1.2, -1.2,
3362                0.0000000012344501, -0.0000000012344501,
3363                123445.01, -123445.01,
3364                12344501000000000000000000000000000.0, -12344501000000000000000000000000000.0,
3365        };
3366        String[] expected = {
3367                "0.00", "0.00",
3368                "123", "-123",
3369                "12345", "-12345",
3370                "123.45", "-123.45",
3371                "123.45", "-123.45",
3372                "0.001234", "-0.001234",
3373                "0.00000000123", "-0.00000000123",
3374                "0.0000000000000000000123", "-0.0000000000000000000123",
3375                "1.20", "-1.20",
3376                "0.0000000012345", "-0.0000000012345",
3377                "123450", "-123450",
3378                "12345000000000000000000000000000000", "-12345000000000000000000000000000000",
3379        };
3380        DecimalFormat numberFormat =
3381                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
3382        numberFormat.setSignificantDigitsUsed(true);
3383        numberFormat.setMinimumSignificantDigits(3);
3384        numberFormat.setMaximumSignificantDigits(5);
3385        numberFormat.setGroupingUsed(false);
3386        for (int i = 0; i < input.length; i++) {
3387            assertEquals("TestSignificantDigits", expected[i], numberFormat.format(input[i]));
3388        }
3389    }
3390
3391    public void TestBug9936() {
3392        DecimalFormat numberFormat =
3393                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
3394        assertFalse("", numberFormat.areSignificantDigitsUsed());
3395
3396        numberFormat.setSignificantDigitsUsed(true);
3397        assertTrue("", numberFormat.areSignificantDigitsUsed());
3398
3399        numberFormat.setSignificantDigitsUsed(false);
3400        assertFalse("", numberFormat.areSignificantDigitsUsed());
3401
3402        numberFormat.setMinimumSignificantDigits(3);
3403        assertTrue("", numberFormat.areSignificantDigitsUsed());
3404
3405        numberFormat.setSignificantDigitsUsed(false);
3406        numberFormat.setMaximumSignificantDigits(6);
3407        assertTrue("", numberFormat.areSignificantDigitsUsed());
3408    }
3409
3410    public void TestShowZero() {
3411        DecimalFormat numberFormat =
3412                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
3413        numberFormat.setSignificantDigitsUsed(true);
3414        numberFormat.setMaximumSignificantDigits(3);
3415        assertEquals("TestShowZero", "0", numberFormat.format(0.0));
3416    }
3417
3418    public void TestCurrencyPlurals() {
3419        String[][] tests = {
3420                {"en", "USD", "1", "1 US dollar"},
3421                {"en", "USD", "1.0", "1.0 US dollars"},
3422                {"en", "USD", "1.00", "1.00 US dollars"},
3423                {"en", "USD", "1.99", "1.99 US dollars"},
3424                {"en", "AUD", "1", "1 Australian dollar"},
3425                {"en", "AUD", "1.00", "1.00 Australian dollars"},
3426                {"sl", "USD", "1", "1 ameri\u0161ki dolar"},
3427                {"sl", "USD", "2", "2 ameri\u0161ka dolarja"},
3428                {"sl", "USD", "3", "3 ameri\u0161ki dolarji"},
3429                {"sl", "USD", "5", "5 ameriških dolarjev"},
3430                {"fr", "USD", "1.99", "1,99 dollar des États-Unis"},
3431                {"ru", "RUB", "1", "1 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0439 \u0440\u0443\u0431\u043B\u044C"},
3432                {"ru", "RUB", "2", "2 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0445 \u0440\u0443\u0431\u043B\u044F"},
3433                {"ru", "RUB", "5", "5 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0445 \u0440\u0443\u0431\u043B\u0435\u0439"},
3434        };
3435        for (String test[] : tests) {
3436            DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getInstance(new ULocale(test[0]), NumberFormat.PLURALCURRENCYSTYLE);
3437            numberFormat.setCurrency(Currency.getInstance(test[1]));
3438            double number = Double.parseDouble(test[2]);
3439            int dotPos = test[2].indexOf('.');
3440            int decimals = dotPos < 0 ? 0 : test[2].length() - dotPos - 1;
3441            int digits = dotPos < 0 ? test[2].length() : test[2].length() - 1;
3442            numberFormat.setMaximumFractionDigits(decimals);
3443            numberFormat.setMinimumFractionDigits(decimals);
3444            String actual = numberFormat.format(number);
3445            assertEquals(test[0] + "\t" + test[1] + "\t" + test[2], test[3], actual);
3446            numberFormat.setMaximumSignificantDigits(digits);
3447            numberFormat.setMinimumSignificantDigits(digits);
3448            actual = numberFormat.format(number);
3449            assertEquals(test[0] + "\t" + test[1] + "\t" + test[2], test[3], actual);
3450        }
3451    }
3452
3453    public void TestCustomCurrencySignAndSeparator() {
3454        DecimalFormatSymbols custom = new DecimalFormatSymbols(ULocale.US);
3455
3456        custom.setCurrencySymbol("*");
3457        custom.setMonetaryGroupingSeparator('^');
3458        custom.setMonetaryDecimalSeparator(':');
3459
3460        DecimalFormat fmt = new DecimalFormat("\u00A4 #,##0.00", custom);
3461
3462        final String numstr = "* 1^234:56";
3463        expect2(fmt, 1234.56, numstr);
3464    }
3465
3466    public void TestParseSignsAndMarks() {
3467        class SignsAndMarksItem {
3468            public String locale;
3469            public boolean lenient;
3470            public String numString;
3471            public double value;
3472             // Simple constructor
3473            public SignsAndMarksItem(String loc, boolean lnt, String numStr, double val) {
3474                locale = loc;
3475                lenient = lnt;
3476                numString = numStr;
3477                value = val;
3478            }
3479        };
3480        final SignsAndMarksItem[] items = {
3481            // *** Note, ICU4J lenient number parsing does not handle arbitrary whitespace, but can
3482            // treat some whitespace as a grouping separator. The cases marked *** below depend
3483            // on isGroupingUsed() being set for the locale, which in turn depends on grouping
3484            // separators being present in the decimalFormat pattern for the locale (& num sys).
3485            //
3486            //                    locale                lenient numString                               value
3487            new SignsAndMarksItem("en",                 false,  "12",                                    12 ),
3488            new SignsAndMarksItem("en",                 true,   "12",                                    12 ),
3489            new SignsAndMarksItem("en",                 false,  "-23",                                  -23 ),
3490            new SignsAndMarksItem("en",                 true,   "-23",                                  -23 ),
3491            new SignsAndMarksItem("en",                 true,   "- 23",                                 -23 ), // ***
3492            new SignsAndMarksItem("en",                 false,  "\u200E-23",                            -23 ),
3493            new SignsAndMarksItem("en",                 true,   "\u200E-23",                            -23 ),
3494            new SignsAndMarksItem("en",                 true,   "\u200E- 23",                           -23 ), // ***
3495
3496            new SignsAndMarksItem("en@numbers=arab",    false,  "\u0663\u0664",                          34 ),
3497            new SignsAndMarksItem("en@numbers=arab",    true,   "\u0663\u0664",                          34 ),
3498            new SignsAndMarksItem("en@numbers=arab",    false,  "-\u0664\u0665",                        -45 ),
3499            new SignsAndMarksItem("en@numbers=arab",    true,   "-\u0664\u0665",                        -45 ),
3500            new SignsAndMarksItem("en@numbers=arab",    true,   "- \u0664\u0665",                       -45 ), // ***
3501            new SignsAndMarksItem("en@numbers=arab",    false,  "\u200F-\u0664\u0665",                  -45 ),
3502            new SignsAndMarksItem("en@numbers=arab",    true,   "\u200F-\u0664\u0665",                  -45 ),
3503            new SignsAndMarksItem("en@numbers=arab",    true,   "\u200F- \u0664\u0665",                 -45 ), // ***
3504
3505            new SignsAndMarksItem("en@numbers=arabext", false,  "\u06F5\u06F6",                          56 ),
3506            new SignsAndMarksItem("en@numbers=arabext", true,   "\u06F5\u06F6",                          56 ),
3507            new SignsAndMarksItem("en@numbers=arabext", false,  "-\u06F6\u06F7",                        -67 ),
3508            new SignsAndMarksItem("en@numbers=arabext", true,   "-\u06F6\u06F7",                        -67 ),
3509            new SignsAndMarksItem("en@numbers=arabext", true,   "- \u06F6\u06F7",                       -67 ), // ***
3510            new SignsAndMarksItem("en@numbers=arabext", false,  "\u200E-\u200E\u06F6\u06F7",            -67 ),
3511            new SignsAndMarksItem("en@numbers=arabext", true,   "\u200E-\u200E\u06F6\u06F7",            -67 ),
3512            new SignsAndMarksItem("en@numbers=arabext", true,   "\u200E-\u200E \u06F6\u06F7",           -67 ), // ***
3513
3514            new SignsAndMarksItem("he",                 false,  "12",                                    12 ),
3515            new SignsAndMarksItem("he",                 true,   "12",                                    12 ),
3516            new SignsAndMarksItem("he",                 false,  "-23",                                  -23 ),
3517            new SignsAndMarksItem("he",                 true,   "-23",                                  -23 ),
3518            new SignsAndMarksItem("he",                 true,   "- 23",                                 -23 ), // ***
3519            new SignsAndMarksItem("he",                 false,  "\u200E-23",                            -23 ),
3520            new SignsAndMarksItem("he",                 true,   "\u200E-23",                            -23 ),
3521            new SignsAndMarksItem("he",                 true,   "\u200E- 23",                           -23 ), // ***
3522
3523            new SignsAndMarksItem("ar",                 false,  "\u0663\u0664",                          34 ),
3524            new SignsAndMarksItem("ar",                 true,   "\u0663\u0664",                          34 ),
3525            new SignsAndMarksItem("ar",                 false,  "-\u0664\u0665",                        -45 ),
3526            new SignsAndMarksItem("ar",                 true,   "-\u0664\u0665",                        -45 ),
3527            new SignsAndMarksItem("ar",                 true,   "- \u0664\u0665",                       -45 ), // ***
3528            new SignsAndMarksItem("ar",                 false,  "\u200F-\u0664\u0665",                  -45 ),
3529            new SignsAndMarksItem("ar",                 true,   "\u200F-\u0664\u0665",                  -45 ),
3530            new SignsAndMarksItem("ar",                 true,   "\u200F- \u0664\u0665",                 -45 ), // ***
3531
3532            new SignsAndMarksItem("ar_MA",              false,  "12",                                    12 ),
3533            new SignsAndMarksItem("ar_MA",              true,   "12",                                    12 ),
3534            new SignsAndMarksItem("ar_MA",              false,  "-23",                                  -23 ),
3535            new SignsAndMarksItem("ar_MA",              true,   "-23",                                  -23 ),
3536            new SignsAndMarksItem("ar_MA",              true,   "- 23",                                 -23 ), // ***
3537            new SignsAndMarksItem("ar_MA",              false,  "\u200E-23",                            -23 ),
3538            new SignsAndMarksItem("ar_MA",              true,   "\u200E-23",                            -23 ),
3539            new SignsAndMarksItem("ar_MA",              true,   "\u200E- 23",                           -23 ), // ***
3540
3541            new SignsAndMarksItem("fa",                 false,  "\u06F5\u06F6",                          56 ),
3542            new SignsAndMarksItem("fa",                 true,   "\u06F5\u06F6",                          56 ),
3543            new SignsAndMarksItem("fa",                 false,  "\u2212\u06F6\u06F7",                   -67 ),
3544            new SignsAndMarksItem("fa",                 true,   "\u2212\u06F6\u06F7",                   -67 ),
3545            new SignsAndMarksItem("fa",                 true,   "\u2212 \u06F6\u06F7",                  -67 ), // ***
3546            new SignsAndMarksItem("fa",                 false,  "\u200E\u2212\u200E\u06F6\u06F7",       -67 ),
3547            new SignsAndMarksItem("fa",                 true,   "\u200E\u2212\u200E\u06F6\u06F7",       -67 ),
3548            new SignsAndMarksItem("fa",                 true,   "\u200E\u2212\u200E \u06F6\u06F7",      -67 ), // ***
3549
3550            new SignsAndMarksItem("ps",                 false,  "\u06F5\u06F6",                          56 ),
3551            new SignsAndMarksItem("ps",                 true,   "\u06F5\u06F6",                          56 ),
3552            new SignsAndMarksItem("ps",                 false,  "-\u06F6\u06F7",                        -67 ),
3553            new SignsAndMarksItem("ps",                 true,   "-\u06F6\u06F7",                        -67 ),
3554            new SignsAndMarksItem("ps",                 true,   "- \u06F6\u06F7",                       -67 ), // ***
3555            new SignsAndMarksItem("ps",                 false,  "\u200E-\u200E\u06F6\u06F7",            -67 ),
3556            new SignsAndMarksItem("ps",                 true,   "\u200E-\u200E\u06F6\u06F7",            -67 ),
3557            new SignsAndMarksItem("ps",                 true,   "\u200E-\u200E \u06F6\u06F7",           -67 ), // ***
3558            new SignsAndMarksItem("ps",                 false,  "-\u200E\u06F6\u06F7",                  -67 ),
3559            new SignsAndMarksItem("ps",                 true,   "-\u200E\u06F6\u06F7",                  -67 ),
3560            new SignsAndMarksItem("ps",                 true,   "-\u200E \u06F6\u06F7",                 -67 ), // ***
3561        };
3562        for (SignsAndMarksItem item: items) {
3563            ULocale locale = new ULocale(item.locale);
3564            NumberFormat numfmt = NumberFormat.getInstance(locale);
3565            if (numfmt != null) {
3566                numfmt.setParseStrict(!item.lenient);
3567                ParsePosition ppos = new ParsePosition(0);
3568                Number num = numfmt.parse(item.numString, ppos);
3569                if (num != null && ppos.getIndex() == item.numString.length()) {
3570                    double parsedValue = num.doubleValue();
3571                    if (parsedValue != item.value) {
3572                        errln("FAIL: locale " + item.locale + ", lenient " + item.lenient + ", parse of \"" + item.numString + "\" gives value " + parsedValue);
3573                    }
3574                } else {
3575                    errln("FAIL: locale " + item.locale + ", lenient " + item.lenient + ", parse of \"" + item.numString + "\" gives position " + ppos.getIndex());
3576                }
3577            } else {
3578                errln("FAIL: NumberFormat.getInstance for locale " + item.locale);
3579            }
3580        }
3581    }
3582
3583    public void TestContext() {
3584        // just a minimal sanity check for now
3585        NumberFormat nfmt = NumberFormat.getInstance();
3586        DisplayContext context = nfmt.getContext(DisplayContext.Type.CAPITALIZATION);
3587        if (context != DisplayContext.CAPITALIZATION_NONE) {
3588            errln("FAIL: Initial NumberFormat.getContext() is not CAPITALIZATION_NONE");
3589        }
3590        nfmt.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
3591        context = nfmt.getContext(DisplayContext.Type.CAPITALIZATION);
3592        if (context != DisplayContext.CAPITALIZATION_FOR_STANDALONE) {
3593            errln("FAIL: NumberFormat.getContext() does not return the value set, CAPITALIZATION_FOR_STANDALONE");
3594        }
3595    }
3596
3597    public void TestAccountingCurrency() {
3598        String[][] tests = {
3599                {"en_US", "1234.5", "$1,234.50", "true"},
3600                {"en_US", "-1234.5", "($1,234.50)", "true"},
3601                {"en_US", "0", "$0.00", "true"},
3602                {"en_US", "-0.2", "($0.20)", "true"},
3603                {"ja_JP", "10000", "¥10,000", "true"},
3604                {"ja_JP", "-1000.5", "(¥1,000)", "false"},
3605                {"de_DE", "-23456.7", "-23.456,70\u00A0€", "true"},
3606        };
3607        for (String[] data : tests) {
3608            ULocale loc = new ULocale(data[0]);
3609            double num = Double.parseDouble(data[1]);
3610            String fmt = data[2];
3611            boolean rt = Boolean.parseBoolean(data[3]);
3612
3613            NumberFormat acfmt = NumberFormat.getInstance(loc, NumberFormat.ACCOUNTINGCURRENCYSTYLE);
3614            expect(acfmt, num, fmt, rt);
3615        }
3616    }
3617
3618    public void TestCurrencyUsage() {
3619        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
3620        // compare the Currency and Currency Cash Digits
3621        // Note that as of CLDR 26:
3622        // * TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
3623        // * CAD and all other currencies that rounded to .05 no longer do
3624        for (int i = 0; i < 2; i++) {
3625            String original_expected = "PKR124";
3626            DecimalFormat custom = null;
3627            if (i == 0) {
3628                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=PKR"),
3629                        DecimalFormat.CURRENCYSTYLE);
3630
3631                String original = custom.format(123.567);
3632                assertEquals("Test Currency Context", original_expected, original);
3633
3634                // test the getter
3635                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(),
3636                        Currency.CurrencyUsage.STANDARD);
3637                custom.setCurrencyUsage(Currency.CurrencyUsage.CASH);
3638                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
3639            } else {
3640                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=PKR"),
3641                        DecimalFormat.CASHCURRENCYSTYLE);
3642
3643                // test the getter
3644                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
3645            }
3646
3647            String cash_currency = custom.format(123.567);
3648            String cash_currency_expected = "PKR124";
3649            assertEquals("Test Currency Context", cash_currency_expected, cash_currency);
3650        }
3651
3652        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
3653        // compare the Currency and Currency Cash Rounding
3654        for (int i = 0; i < 2; i++) {
3655            String original_rounding_expected = "CA$123.57";
3656            DecimalFormat fmt = null;
3657            if (i == 0) {
3658                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
3659                        DecimalFormat.CURRENCYSTYLE);
3660
3661                String original_rounding = fmt.format(123.566);
3662                assertEquals("Test Currency Context", original_rounding_expected, original_rounding);
3663
3664                fmt.setCurrencyUsage(Currency.CurrencyUsage.CASH);
3665            } else {
3666                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
3667                        DecimalFormat.CASHCURRENCYSTYLE);
3668            }
3669
3670            String cash_rounding_currency = fmt.format(123.567);
3671            String cash__rounding_currency_expected = "CA$123.57";
3672            assertEquals("Test Currency Context", cash__rounding_currency_expected, cash_rounding_currency);
3673        }
3674
3675        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
3676        // Test the currency change
3677        for (int i = 0; i < 2; i++) {
3678            DecimalFormat fmt2 = null;
3679            if (i == 1) {
3680                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
3681                        NumberFormat.CURRENCYSTYLE);
3682                fmt2.setCurrencyUsage(Currency.CurrencyUsage.CASH);
3683            } else {
3684                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
3685                        NumberFormat.CASHCURRENCYSTYLE);
3686            }
3687
3688            fmt2.setCurrency(Currency.getInstance("PKR"));
3689            String PKR_changed = fmt2.format(123.567);
3690            String PKR_changed_expected = "PKR124";
3691            assertEquals("Test Currency Context", PKR_changed_expected, PKR_changed);
3692        }
3693    }
3694
3695    public void TestParseRequiredDecimalPoint() {
3696
3697        String[] testPattern = { "00.####", "00.0", "00" };
3698
3699        String value2Parse = "99";
3700        double parseValue  =  99;
3701        DecimalFormat parser = new DecimalFormat();
3702        double result;
3703        boolean hasDecimalPoint;
3704        for (int i = 0; i < testPattern.length; i++) {
3705            parser.applyPattern(testPattern[i]);
3706            hasDecimalPoint = testPattern[i].contains(".");
3707
3708            parser.setDecimalPatternMatchRequired(false);
3709            try {
3710                result = parser.parse(value2Parse).doubleValue();
3711                assertEquals("wrong parsed value", parseValue, result);
3712            } catch (ParseException e) {
3713               this.errln("Parsing " + value2Parse + " should have succeeded with " + testPattern[i] +
3714                            " and isDecimalPointMatchRequired set to: " + parser.isDecimalPatternMatchRequired());
3715            }
3716
3717            parser.setDecimalPatternMatchRequired(true);
3718            try {
3719                result = parser.parse(value2Parse).doubleValue();
3720                if(hasDecimalPoint){
3721                    this.errln("Parsing " + value2Parse + " should NOT have succeeded with " + testPattern[i] +
3722                            " and isDecimalPointMatchRequired set to: " + parser.isDecimalPatternMatchRequired());
3723                }
3724            } catch (ParseException e) {
3725                    // OK, should fail
3726            }
3727        }
3728
3729    }
3730
3731    public void TestCurrFmtNegSameAsPositive() {
3732        DecimalFormatSymbols decfmtsym = DecimalFormatSymbols.getInstance(Locale.US);
3733        decfmtsym.setMinusSign('\u200B'); // ZERO WIDTH SPACE, in ICU4J cannot set to empty string
3734        DecimalFormat decfmt = new DecimalFormat("\u00A4#,##0.00;\u00A4#,##0.00", decfmtsym);
3735        String currFmtResult = decfmt.format(-100.0);
3736        if (!currFmtResult.equals("\u200B$100.00")) {
3737            errln("decfmt.toPattern results wrong, expected \u200B$100.00, got " + currFmtResult);
3738        }
3739    }
3740
3741}
3742