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