2 *******************************************************************************
3 * Copyright (C) 2001-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 * Port From: ICU4C v1.8.1 : format : NumberFormatTest
10 * Source File: $ICU4CRoot/source/test/intltest/numfmtst.cpp
13 package com.ibm.icu.dev.test.format;
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;
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;
40 public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
42 public static void main(String[] args) throws Exception {
43 new NumberFormatTest().run(args);
46 public void TestParseNegativeWithFaLocale() {
47 DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("fa"));
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.");
56 public void TestParseNegativeWithAlternativeMinusSign() {
57 DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("en"));
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.");
66 // Test various patterns
67 public void TestPatterns() {
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)
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");
82 String s = ((NumberFormat)fmt).format(0);
83 if (!s.equals(num[i]))
85 errln("FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
86 "; " + s + " seen instead");
87 logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
89 // BigInteger 0 - ticket#4731
90 s = ((NumberFormat)fmt).format(BigInteger.ZERO);
91 if (!s.equals(num[i]))
93 errln("FAIL: Pattern " + pat[i] + " should format BigInteger zero as " + num[i] +
94 "; " + s + " seen instead");
95 logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
100 // Test exponential pattern
101 public void TestExponential() {
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;
107 double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
108 int val_length = val.length;
109 final String valFormat[] = {
111 "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
113 "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
115 "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
117 "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" };
118 /*double valParse[] =
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
126 int lval[] = { 0, -1, 1, 123456789 };
127 int lval_length = lval.length;
128 final String lvalFormat[] = {
130 "0E0", "-1E0", "1E0", "1.2346E8",
132 "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
134 "0E000", "-1E000", "1E000", "123.4568E006",
136 "0E0", "[1E0]", "1E0", "1.235E8" };
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() + "\"");
149 for (v = 0; v < val_length; ++v) {
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]);
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
162 errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
164 for (v = 0; v < lval_length; ++v) {
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);
171 ParsePosition pos = new ParsePosition(0);
173 Number A = fmt.parse(s, pos);
176 if (pos.getIndex() == s.length()) {
177 logln(" -parse-> " + a);
178 if (a != lvalParse[v + ilval])
179 errln("FAIL: Expected " + lvalParse[v + ilval]);
181 errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + Long.toString(a));
183 errln("Fail to parse the string: " + s);
187 ilval += lval_length;
191 // Test the handling of quotes
192 public void TestQuotes() {
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");
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");
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);
221 Number num = fmt.parse(str);
222 logln("num: " + num);
223 } catch (ParseException e) {
224 errln("parse of '" + str + "' threw exception: " + e);
229 * Test the handling of the currency symbol in patterns.
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);
244 s = ((NumberFormat) fmt).format(-1234.56);
245 logln(" Format " + Double.toString(-1234.56) + " . " + s);
246 assertEquals("symbol, neg", "-$1,234.56", s);
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);
257 s = ((NumberFormat) fmt).format(-1234.56);
258 logln(" Format " + Double.toString(-1234.56) + " . " + s);
259 assertEquals("name, neg", "USD -1,234.56", s);
262 public void TestSpaceParsing() {
264 // the string to be parsed, parsed position, parsed error index
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?
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]);
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());
288 if (parsePosition.getErrorIndex() == -1 &&
289 result.doubleValue() != 124) {
290 errln("FAILED parse " + stringToBeParsed + "; value " + result.doubleValue());
292 } catch (Exception e) {
293 errln("FAILED " + e.toString());
299 public void TestMultiCurrencySign() {
301 // the fields in the following test are:
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".
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"},
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"}
318 String doubleCurrencyStr = "\u00A4\u00A4";
319 String tripleCurrencyStr = "\u00A4\u00A4\u00A4";
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.
329 pat = pat.replaceAll("\u00A4", doubleCurrencyStr);
331 pat = pat.replaceAll("\u00A4\u00A4", tripleCurrencyStr);
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);
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);
362 } catch (ParseException e) {
363 errln("FAILED, DecimalFormat parse currency: " + e.toString());
369 public void TestCurrencyFormatForMixParsing() {
370 MeasureFormat curFmt = MeasureFormat.getCurrencyFormat(new ULocale("en_US"));
372 "$1,234.56", // string to be parsed
374 "US dollars1,234.56",
375 "1,234.56 US dollars"
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);
385 if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
386 errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
389 } catch (ParseException e) {
390 errln("parse FAILED: " + e.toString());
394 public void TestDecimalFormatCurrencyParse() {
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);
404 // string to be parsed, the parsed result (number)
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"},
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);
421 } catch (ParseException e) {
422 errln("FAILED, DecimalFormat parse currency: " + e.toString());
427 * Test localized currency patterns.
429 public void TestCurrency() {
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",
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);
445 logln("FAIL: 1.50 x " + locale + " => " + s +
446 ", expected " + DATA[i+3]);
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]);
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
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);
464 errln("FAIL: 1.50 x " + locale + " => " + sCurr +
465 ", expected " + DATA[i+3]);
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")));
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);
481 if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
482 errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
485 catch (ParseException e) {
486 errln("FAIL: " + e.getMessage());
488 ULocale.setDefault(save);
491 public void TestCurrencyIsoPluralFormat() {
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 ١٫٠٠", "١٫٠٠ دولار أمريكي"},
518 for (int i=0; i<DATA.length; ++i) {
519 for (int k = NumberFormat.CURRENCYSTYLE;
520 k <= NumberFormat.PLURALCURRENCYSTYLE;
522 // k represents currency format style.
523 if ( k != NumberFormat.CURRENCYSTYLE &&
524 k != NumberFormat.ISOCURRENCYSTYLE &&
525 k != NumberFormat.PLURALCURRENCYSTYLE ) {
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;
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);
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);
561 catch (ParseException e) {
562 errln("FAIL: " + e.getMessage());
569 public void TestMiscCurrencyParsing() {
571 // each has: string to be parsed, parsed position, error position
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"},
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());
591 if (parsePosition.getErrorIndex() == -1 &&
592 val.doubleValue() != 1.00) {
593 errln("FAIL: parse failed. expected 1.00, actual:" + val);
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;
609 ParseCurrencyItem(String locStr, String desc, String curr, int numExPos, int numExVal, int curExPos, int curExVal, String curExCurr) {
610 localeString = locStr;
613 numExpectPos = numExPos;
614 numExpectVal = numExVal;
615 curExpectPos = curExPos;
616 curExpectVal = curExVal;
617 curExpectCurr = curExCurr;
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; }
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" ),
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" ),
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, "" ),
651 for (ParseCurrencyItem item: parseCurrencyItems) {
652 String localeString = item.getLocaleString();
653 ULocale uloc = new ULocale(localeString);
654 NumberFormat fmt = null;
656 fmt = NumberFormat.getCurrencyInstance(uloc);
657 } catch (Exception e) {
658 errln("NumberFormat.getCurrencyInstance fails for locale " + localeString);
661 String currStr = item.getCurrStr();
662 ParsePosition parsePos = new ParsePosition(0);
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() );
671 errln("NumberFormat.getCurrencyInstance parse " + localeString + "/" + item.getDescrip() +
672 ", expect pos/val " + item.getNumExpectPos() + "/" + item.getNumExpectVal() +
673 ", get " + parsePos.getIndex() + "/(NULL)" );
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() );
686 errln("NumberFormat.getCurrencyInstance parseCurrency " + localeString + "/" + item.getDescrip() +
687 ", expect pos/val/curr " + item.getCurExpectPos() + "/" + item.getCurExpectVal() + "/" + item.getCurExpectCurr() +
688 ", get " + parsePos.getIndex() + "/(NULL)" );
695 * Test the Currency object handling, new as of ICU 2.2.
697 public void TestCurrencyObject() {
699 NumberFormat.getCurrencyInstance(Locale.US);
701 expectCurrency(fmt, null, 1234.56, "$1,234.56");
703 expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
704 1234.56, "\u20AC1,234.56"); // Euro
706 expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
707 1234.56, "\u00A51,235"); // Yen
709 expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
710 1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
712 expectCurrency(fmt, Currency.getInstance(Locale.US),
713 1234.56, "$1,234.56");
715 fmt = NumberFormat.getCurrencyInstance(Locale.FRANCE);
717 expectCurrency(fmt, null, 1234.56, "1 234,56 \u20AC");
719 expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
720 1234.56, "1 235 \u00A5JP"); // Yen
722 expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
723 1234.56, "1 234,56 CHF"); // no more rounding here, see cldrbug 5548
725 expectCurrency(fmt, Currency.getInstance(Locale.US),
726 1234.56, "1 234,56 $US");
728 expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
729 1234.56, "1 234,56 \u20AC"); // Euro
732 public void TestCompatibleCurrencies() {
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
739 public void TestCurrencyPatterns() {
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();
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; "+
754 "; x 1.125 => " + b);
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; "+
774 * Do rudimentary testing of parsing.
776 public void TestParse() {
778 DecimalFormat format = new DecimalFormat("00");
781 aNumber = format.parse(arg).doubleValue();
782 } catch (ParseException e) {
783 System.out.println(e);
785 logln("parse(" + arg + ") = " + aNumber);
789 * Test proper rounding by the format method.
791 public void TestRounding487() {
793 NumberFormat nf = NumberFormat.getInstance();
794 roundingTest(nf, 0.00159999, 4, "0.0016");
795 roundingTest(nf, 0.00995, 4, "0.01");
797 roundingTest(nf, 12.3995, 3, "12.4");
799 roundingTest(nf, 12.4999, 0, "12");
800 roundingTest(nf, - 19.5, 0, "-20");
805 * Test the functioning of the secondary grouping value.
807 public void TestSecondaryGrouping() {
809 DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
810 DecimalFormat f = new DecimalFormat("#,##,###", US);
812 expect(f, 123456789L, "12,34,56,789");
813 expectPat(f, "#,##,###");
814 f.applyPattern("#,###");
816 f.setSecondaryGroupingSize(4);
817 expect(f, 123456789L, "12,3456,789");
818 expectPat(f, "#,####,###");
819 NumberFormat g = NumberFormat.getInstance(new Locale("hi", "IN"));
822 long l = 1876543210L;
825 // expect "1,87,65,43,210", but with Hindi digits
828 if (out.length() != 14) {
831 for (int i = 0; i < out.length(); ++i) {
832 boolean expectGroup = false;
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) {
851 errln("FAIL Expected "+ l + " x hi_IN . \"1,87,65,43,210\" (with Hindi digits), got \""
854 logln("Ok " + l + " x hi_IN . \"" + out + "\"");
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);
867 * Upgrade to alphaWorks
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);
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"
881 * Upgrade to alphaWorks
883 public void TestScientific() {
885 DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
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;
891 // min int, max int, min frac, max frac
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]"
898 for (int i = 0; i < PAT_length; ++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 + "\"");
905 errln("FAIL Pattern rt \"" + pat + "\" . \"" + pat2 + "\"");
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]);
924 expect2(new DecimalFormat("#E0", US), 12345.0, "1.2345E4");
925 expect(new DecimalFormat("0E0", US), 12345.0, "1E4");
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");
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");
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");
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");
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),
958 new String[] { "4.5678E7",
967 ! Unroll this test into individual tests below...
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");
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",
989 ! Unroll this test into individual tests below...
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");
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",
1007 ! Unroll this test into individual tests below...
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");
1015 * Upgrade to alphaWorks
1017 public void TestPad() {
1019 DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1020 expect2(new DecimalFormat("*^##.##", US), 0, "^^^^0");
1021 expect2(new DecimalFormat("*^##.##", US), -1.3, "^-1.3");
1023 new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
1025 "0.0E0______ g-m/s^2");
1027 new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
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");
1032 new DecimalFormat("##0.0####*_ 'g-m/s^2'", US),
1034 "0.33333__ g-m/s^2");
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)");
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");
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)");
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");
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)"^^^");
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);
1097 * Upgrade to alphaWorks
1099 public void TestPatterns2() {
1100 DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1101 DecimalFormat fmt = new DecimalFormat("#", US);
1103 char hat = 0x005E; /*^*/
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*/);
1115 fmt.applyPattern("AA#,##0.00ZZ");
1116 fmt.setPadCharacter(hat);
1118 fmt.setFormatWidth(10);
1120 fmt.setPadPosition(DecimalFormat.PAD_BEFORE_PREFIX);
1121 expectPat(fmt, "*^AA#,##0.00ZZ");
1123 fmt.setPadPosition(DecimalFormat.PAD_BEFORE_SUFFIX);
1124 expectPat(fmt, "AA#,##0.00*^ZZ");
1126 fmt.setPadPosition(DecimalFormat.PAD_AFTER_SUFFIX);
1127 expectPat(fmt, "AA#,##0.00ZZ*^");
1130 String exp = "AA*^#,##0.00ZZ";
1131 fmt.setFormatWidth(12);
1132 fmt.setPadPosition(DecimalFormat.PAD_AFTER_PREFIX);
1133 expectPat(fmt, exp);
1135 fmt.setFormatWidth(13);
1137 expectPat(fmt, "AA*^##,##0.00ZZ");
1139 fmt.setFormatWidth(14);
1141 expectPat(fmt, "AA*^###,##0.00ZZ");
1143 fmt.setFormatWidth(15);
1145 expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
1147 fmt.setFormatWidth(16);
1148 // 12 34567890123456
1149 expectPat(fmt, "AA*^#,###,##0.00ZZ");
1152 public void TestRegistration() {
1153 final ULocale SRC_LOC = ULocale.FRANCE;
1154 final ULocale SWAP_LOC = ULocale.US;
1156 class TestFactory extends SimpleNumberFormatFactory {
1157 NumberFormat currencyStyle;
1160 super(SRC_LOC, true);
1161 currencyStyle = NumberFormat.getIntegerInstance(SWAP_LOC);
1165 public NumberFormat createFormat(ULocale loc, int formatType) {
1166 if (formatType == FORMAT_CURRENCY) {
1167 return currencyStyle;
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);
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));
1190 if (!f3.format(n).equals(f0.format(n))) {
1191 errln("registered service did not match");
1193 if (!f4.format(n).equals(f1.format(n))) {
1194 errln("registered service did not inherit");
1196 if (!f5.format(n).equals(f2.format(n))) {
1197 errln("unregistered service did not match original");
1201 public void TestScientific2() {
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");
1212 public void TestScientificGrouping() {
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");
1223 // additional coverage tests
1225 // sigh, can't have static inner classes, why not?
1227 static final class PI extends Number {
1231 private static final long serialVersionUID = -305601227915602172L;
1235 public int intValue() { return (int)Math.PI; }
1237 public long longValue() { return (long)Math.PI; }
1239 public float floatValue() { return (float)Math.PI; }
1241 public double doubleValue() { return Math.PI; }
1243 public byte byteValue() { return (byte)Math.PI; }
1245 public short shortValue() { return (short)Math.PI; }
1247 public static final Number INSTANCE = new PI();
1250 public void TestCoverage() {
1251 NumberFormat fmt = NumberFormat.getNumberInstance(); // default locale
1252 logln(fmt.format(new BigInteger("1234567890987654321234567890987654321", 10)));
1254 fmt = NumberFormat.getScientificInstance(); // default locale
1256 logln(fmt.format(PI.INSTANCE));
1259 logln(fmt.format("12345"));
1260 errln("numberformat of string did not throw exception");
1262 catch (Exception e) {
1263 logln("PASS: numberformat of string failed as expected");
1266 int hash = fmt.hashCode();
1267 logln("hash code " + hash);
1269 logln("compare to string returns: " + fmt.equals(""));
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 '&*");
1281 java.math.BigDecimal r;
1283 r = df.getRoundingIncrement();
1285 errln("FAIL: rounding = " + r + ", expect null");
1288 if (df.isScientificNotation()) {
1289 errln("FAIL: isScientificNotation = true, expect false");
1292 df.applyPattern("0.00000");
1293 df.setScientificNotation(true);
1294 if (!df.isScientificNotation()) {
1295 errln("FAIL: isScientificNotation = false, expect true");
1297 df.setMinimumExponentDigits((byte)2);
1298 if (df.getMinimumExponentDigits() != 2) {
1299 errln("FAIL: getMinimumExponentDigits = " +
1300 df.getMinimumExponentDigits() + ", expect 2");
1302 df.setExponentSignAlwaysShown(true);
1303 if (!df.isExponentSignAlwaysShown()) {
1304 errln("FAIL: isExponentSignAlwaysShown = false, expect true");
1306 df.setSecondaryGroupingSize(0);
1307 if (df.getSecondaryGroupingSize() != 0) {
1308 errln("FAIL: getSecondaryGroupingSize = " +
1309 df.getSecondaryGroupingSize() + ", expect 0");
1311 expect2(df, 3.14159, "3.14159E+00");
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().");
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).");
1327 // DecimalFormatSymbols#getAvailableLocales/#getAvailableULocales
1328 Locale[] allLocales = DecimalFormatSymbols.getAvailableLocales();
1329 if (allLocales.length == 0) {
1330 errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1332 logln("PASS: " + allLocales.length +
1333 " available locales returned by DecimalFormatSymbols.getAvailableLocales");
1335 ULocale[] allULocales = DecimalFormatSymbols.getAvailableULocales();
1336 if (allULocales.length == 0) {
1337 errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1339 logln("PASS: " + allULocales.length +
1340 " available locales returned by DecimalFormatSymbols.getAvailableULocales");
1344 public void TestWhiteSpaceParsing() {
1345 DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1346 DecimalFormat fmt = new DecimalFormat("a b#0c ", US);
1348 expect(fmt, "a b1234c ", n);
1349 expect(fmt, "a b1234c ", n);
1353 * Test currencies whose display name is a ChoiceFormat.
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);
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");
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);
1379 * Test alternate numbering systems
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;
1388 TestNumberingSystemItem(String loc, double val, boolean rbnf, String exp) {
1392 expectedResult = exp;
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" )
1415 for (TestNumberingSystemItem item : DATA) {
1416 ULocale loc = new ULocale(item.localeName);
1417 NumberFormat fmt = NumberFormat.getInstance(loc);
1419 expect3(fmt,item.value,item.expectedResult);
1421 expect2(fmt,item.value,item.expectedResult);
1426 public void Test6816() {
1427 Currency cur1 = Currency.getInstance(new Locale("und", "PH"));
1429 NumberFormat nfmt = NumberFormat.getCurrencyInstance(new Locale("und", "PH"));
1430 DecimalFormatSymbols decsym = ((DecimalFormat)nfmt).getDecimalFormatSymbols();
1431 Currency cur2 = decsym.getCurrency();
1433 if ( !cur1.getCurrencyCode().equals("PHP") || !cur2.getCurrencyCode().equals("PHP")) {
1434 errln("FAIL: Currencies should match PHP: cur1 = "+cur1.getCurrencyCode()+"; cur2 = "+cur2.getCurrencyCode());
1439 public void TestThreadedFormat() {
1441 class FormatTask implements Runnable {
1447 FormatTask(DecimalFormat fmt, int index) {
1449 this.buf = new StringBuffer();
1450 this.inc = (index & 0x1) == 0;
1451 this.num = inc ? 0 : 10000;
1456 while (num < 10000) {
1457 buf.append(fmt.format(num) + "\n");
1462 buf.append(fmt.format(num) + "\n");
1469 return buf.toString();
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);
1479 TestUtil.runUntilDone(tasks);
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");
1496 public void TestPerMill() {
1497 DecimalFormat fmt = new DecimalFormat("###.###\u2030");
1498 assertEquals("0.4857 x ###.###\u2030",
1499 "485.7\u2030", fmt.format(0.4857));
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));
1509 public void TestIllegalPatterns() {
1511 // Prefix with "-:" for illegal patterns
1512 // Prefix with "+:" for legal patterns
1514 // Unquoted special characters in the suffix are illegal
1518 for (int i=0; i<DATA.length; ++i) {
1520 boolean valid = pat.charAt(0) == '+';
1521 pat = pat.substring(2);
1524 // locale doesn't matter here
1525 new DecimalFormat(pat);
1526 } catch (IllegalArgumentException e1) {
1528 } catch (IndexOutOfBoundsException e1) {
1531 String msg = (e==null) ? "success" : e.getMessage();
1532 if ((e==null) == valid) {
1533 logln("Ok: pattern \"" + pat + "\": " + msg);
1535 errln("FAIL: pattern \"" + pat + "\" should have " +
1536 (valid?"succeeded":"failed") + "; got " + msg);
1542 * Parse a CurrencyAmount using the given NumberFormat, with
1543 * the 'delim' character separating the number and the currency.
1545 private static CurrencyAmount parseCurrencyAmount(String str, NumberFormat fmt,
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)));
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
1559 private static int keywordIndex(String tok) {
1560 for (int i=0; i<KEYWORDS.length; ++i) {
1561 if (tok.equals(KEYWORDS[i])) {
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
1581 public void TestCases() {
1582 String caseFileName = "NumberFormatTestCases.txt";
1583 java.io.InputStream is = NumberFormatTest.class.getResourceAsStream(caseFileName);
1585 ResourceReader reader = new ResourceReader(is, caseFileName, "utf-8");
1586 TokenIterator tokens = new TokenIterator(reader);
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;
1596 String tok = tokens.next();
1600 String where = "(" + tokens.getLineNumber() + ") ";
1601 int cmd = keywordIndex(tok);
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);
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);
1620 tok = tokens.next();
1621 if (!tok.equals("-")) {
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
1632 if (cmd == 3) tokens.next();
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());
1649 if (cmd != 2) { // != f:
1650 assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
1654 // p: <pattern or '-'> <string to parse> <exp. number>
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 + "\")",
1663 } catch (ParseException e) {
1664 errln(where + '"' + pat + "\".parse(\"" + str +
1665 "\") threw an exception");
1666 e.printStackTrace();
1670 // perr: <pattern or '-'> <invalid string>
1671 errln("Under construction");
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("-")) {
1680 errln("Invalid command \"pat: - err\" at " + tokens.describePosition());
1685 if (exppat.equals("-")) exppat = testpat;
1687 DecimalFormat f = null;
1688 if (testpat == pat) { // [sic]
1691 f = new DecimalFormat(testpat);
1692 f.setParseStrict(strict);
1695 errln(where + "Invalid pattern \"" + testpat +
1698 assertEquals(where + '"' + testpat + "\".toPattern()",
1699 exppat, f.toPattern());
1701 } catch (IllegalArgumentException iae2) {
1703 logln("Ok: " + where + "Invalid pattern \"" + testpat +
1704 "\" threw an exception");
1706 errln(where + "Valid pattern \"" + testpat +
1707 "\" threw an exception");
1708 iae2.printStackTrace();
1713 tok = tokens.next();
1714 if (!tok.equals("-")) {
1716 ULocale l = new ULocale(mloc);
1718 mfmt = MeasureFormat.getCurrencyFormat(l);
1719 } catch (IllegalArgumentException iae) {
1720 errln(where + "Loc \"" + tok + '"');
1721 iae.printStackTrace();
1722 tokens.next(); // consume remaining tokens
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 + ")",
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();
1747 case 9: // strict= true or false
1748 strict = "true".equalsIgnoreCase(tokens.next());
1749 logln("Setting strict to:\t" + strict);
1752 errln("Unknown command \"" + tok + "\" at " + tokens.describePosition());
1756 } catch (java.io.IOException e) {
1757 throw new RuntimeException(e);
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());
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());
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());
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());
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"));
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);
1832 public void TestRoundingPattern() {
1833 class TestRoundingPatternItem {
1835 double roundingIncrement;
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;
1847 TestRoundingPatternItem []tests = {
1848 new TestRoundingPatternItem("##0.65", 0.65, 1.234, "1.30"),
1849 new TestRoundingPatternItem("#50", 50.0, 1230, "1250")
1852 DecimalFormat df = (DecimalFormat) com.ibm.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
1855 for (int i = 0; i < tests.length; i++) {
1856 df.applyPattern(tests[i].pattern);
1858 result = df.format(tests[i].testCase);
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);
1864 bd = new BigDecimal(tests[i].roundingIncrement);
1866 df.setRoundingIncrement(bd);
1868 result = df.format(tests[i].testCase);
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);
1876 public void TestBigDecimalRounding() {
1877 String figure = "50.000000004";
1878 Double dbl = new Double(figure);
1879 BigDecimal dec = new BigDecimal(figure);
1881 DecimalFormat f = (DecimalFormat) NumberFormat.getInstance();
1882 f.applyPattern("00.00######");
1884 assertEquals("double format", "50.00", f.format(dbl));
1885 assertEquals("bigdec format", "50.00", f.format(dec));
1887 int maxFracDigits = f.getMaximumFractionDigits();
1888 BigDecimal roundingIncrement = new BigDecimal("1").movePointLeft(maxFracDigits);
1890 f.setRoundingIncrement(roundingIncrement);
1891 f.setRoundingMode(BigDecimal.ROUND_DOWN);
1892 assertEquals("Rounding down", f.format(dbl), f.format(dec));
1894 f.setRoundingIncrement(roundingIncrement);
1895 f.setRoundingMode(BigDecimal.ROUND_HALF_UP);
1896 assertEquals("Rounding half up", f.format(dbl), f.format(dec));
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
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);
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)) {
1920 errln("Failure at: " + iValue + " (" + iValue.doubleValue() + ")"
1921 + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
1922 + ",\tRounding-increment: " + nf.getRoundingIncrement()
1923 + ",\tdouble: " + formattedDouble
1924 + ",\tBigDecimal: " + formatedBigDecimal);
1927 logln("Value: " + iValue
1928 + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
1929 + ",\tRounding-increment: " + nf.getRoundingIncrement()
1930 + ",\tdouble: " + formattedDouble
1931 + ",\tBigDecimal: " + formatedBigDecimal);
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);
1939 lastParsed = parsed;
1940 } catch (ParseException e) {
1941 errln("Parse Failure with: " + formatedBigDecimal);
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());
1955 static String[] roundingModeNames = {
1956 "ROUND_UP", "ROUND_DOWN", "ROUND_CEILING", "ROUND_FLOOR",
1957 "ROUND_HALF_UP", "ROUND_HALF_DOWN", "ROUND_HALF_EVEN",
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));
1966 private static String stripFinalZeros(String formatted) {
1967 int len1 = formatted.length();
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);
1974 //------------------------------------------------------------------
1976 //------------------------------------------------------------------
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);
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);
1991 // Format-Parse test (convenience)
1992 public void expect2(NumberFormat fmt, double n, String exp) {
1993 expect2(fmt, new Double(n), exp);
1995 // Format-Parse test (convenience)
1996 public void expect3(NumberFormat fmt, double n, String exp) {
1997 expect3(fmt, new Double(n), exp);
2000 // Format-Parse test (convenience)
2001 public void expect2(NumberFormat fmt, long n, String exp) {
2002 expect2(fmt, new Long(n), exp);
2004 // Format-Parse test (convenience)
2005 public void expect3(NumberFormat fmt, long n, String exp) {
2006 expect3(fmt, new Long(n), exp);
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 " +
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):
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 + '"');
2031 } catch (ParseException e) {
2032 errln("expect() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2033 ", " + e.getMessage());
2038 errln("expect() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2039 ", FAIL " + n + " x " + pat + " = \"" + saw + "\", expected \"" + exp + "\"");
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 + " = \"" +
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):
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 + '"');
2062 } catch (ParseException e) {
2063 errln("expect_rbnf() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2064 ", " + e.getMessage());
2069 errln("expect_rbnf() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2070 ", FAIL " + n + " = \"" + saw + "\", expected \"" + exp + "\"");
2074 // Format test (convenience)
2075 public void expect(NumberFormat fmt, Number n, String exp) {
2076 expect(fmt, n, exp, true);
2079 // Format test (convenience)
2080 public void expect(NumberFormat fmt, double n, String exp) {
2081 expect(fmt, new Double(n), exp);
2084 // Format test (convenience)
2085 public void expect(NumberFormat fmt, long n, String exp) {
2086 expect(fmt, new Long(n), exp);
2090 public void expect(NumberFormat fmt, String str, Number n) {
2093 num = fmt.parse(str);
2094 } catch (ParseException e) {
2095 errln(e.getMessage());
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 " +
2106 errln("expect() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2107 ", FAIL \"" + str + "\" x " + pat + " = " + num + ", expected " + n);
2112 public void expect_rbnf(NumberFormat fmt, String str, Number n) {
2115 num = fmt.parse(str);
2116 } catch (ParseException e) {
2117 errln(e.getMessage());
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 + " = " +
2126 errln("expect_rbnf() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2127 ", FAIL \"" + str + " = " + num + ", expected " + n);
2131 // Parse test (convenience)
2132 public void expect(NumberFormat fmt, String str, double n) {
2133 expect(fmt, str, new Double(n));
2136 // Parse test (convenience)
2137 public void expect(NumberFormat fmt, String str, long n) {
2138 expect(fmt, str, new Long(n));
2141 private void expectCurrency(NumberFormat nf, Currency curr,
2142 double value, String string) {
2143 DecimalFormat fmt = (DecimalFormat) nf;
2145 fmt.setCurrency(curr);
2147 String s = fmt.format(value).replace('\u00A0', ' ');
2149 if (s.equals(string)) {
2150 logln("Ok: " + value + " x " + curr + " => " + s);
2152 errln("FAIL: " + value + " x " + curr + " => " + s +
2153 ", expected " + string);
2157 public void expectPad(DecimalFormat fmt, String pat, int pos) {
2158 expectPad(fmt, pat, pos, 0, (char)0);
2161 public void expectPad(DecimalFormat fmt, final String pat, int pos, int width, final char pad) {
2162 int apos = 0, awidth = 0;
2165 fmt.applyPattern(pat);
2166 apos = fmt.getPadPosition();
2167 awidth = fmt.getFormatWidth();
2168 apadStr = fmt.getPadCharacter();
2169 } catch (Exception e) {
2175 if (apos == pos && awidth == width && apadStr == pad) {
2176 logln("Ok \"" + pat + "\" pos="
2177 + apos + ((pos == -1) ? "" : " width=" + awidth + " pad=" + apadStr));
2179 errln("FAIL \"" + pat + "\" pos=" + apos + " width="
2180 + awidth + " pad=" + apadStr + ", expected "
2181 + pos + " " + width + " " + pad);
2185 public void expectPat(DecimalFormat fmt, final String exp) {
2186 String pat = fmt.toPattern();
2187 if (pat.equals(exp)) {
2188 logln("Ok \"" + pat + "\"");
2190 errln("FAIL \"" + pat + "\", expected \"" + exp + "\"");
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());
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);
2216 public void TestStrictParse() {
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
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
2250 DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
2251 runStrictParseBatch(nf, pass, fail);
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 #
2259 String[] scientificFail = {
2260 "1,234E2", // group separators with exponent fail
2263 nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
2264 runStrictParseBatch(nf, scientificPass, scientificFail);
2266 String[] mixedPass = {
2272 String[] mixedFail = {
2279 nf = new DecimalFormat("#,##,##0.#");
2280 runStrictParseBatch(nf, mixedPass, mixedFail);
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);
2292 void runStrictParseTests(String msg, DecimalFormat nf, String[] tests, boolean pass) {
2294 logln("pattern: '" + nf.toPattern() + "'");
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);
2308 if (err.length() > 0) {
2309 err = "got expected " + err;
2311 logln("'" + str + "' parsed '" +
2312 str.substring(0, pp.getIndex()) +
2313 "' returned " + n + " formats to '" +
2314 formatted + "' " + err);
2318 public void TestJB5251(){
2319 //save default locale
2320 ULocale defaultLocale = ULocale.getDefault();
2321 ULocale.setDefault(new ULocale("qr_QR"));
2323 NumberFormat.getInstance();
2325 catch (Exception e) {
2326 errln("Numberformat threw exception for non-existent locale. It should use the default.");
2328 //reset default locale
2329 ULocale.setDefault(defaultLocale);
2332 public void TestParseReturnType() {
2333 String[] defaultNonBigDecimals = {
2337 "12345678901234567890" // BigInteger
2340 String[] doubles = {
2343 "\u221E" // Infinity
2346 DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
2347 DecimalFormat nf = new DecimalFormat("#.#", sym);
2349 if (nf.isParseBigDecimal()) {
2350 errln("FAIL: isParseDecimal() must return false by default");
2353 // isParseBigDecimal() is false
2354 for (int i = 0; i < defaultNonBigDecimals.length; i++) {
2356 Number n = nf.parse(defaultNonBigDecimals[i]);
2357 if (n instanceof BigDecimal) {
2358 errln("FAIL: parse returns BigDecimal instance");
2360 } catch (ParseException e) {
2361 errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
2364 // parse results for doubls must be always Double
2365 for (int i = 0; i < doubles.length; i++) {
2367 Number n = nf.parse(doubles[i]);
2368 if (!(n instanceof Double)) {
2369 errln("FAIL: parse does not return Double instance");
2371 } catch (ParseException e) {
2372 errln("parse of '" + doubles[i] + "' threw exception: " + e);
2376 // force this DecimalFormat to return BigDecimal
2377 nf.setParseBigDecimal(true);
2378 if (!nf.isParseBigDecimal()) {
2379 errln("FAIL: isParseBigDecimal() must return true");
2382 // isParseBigDecimal() is true
2383 for (int i = 0; i < defaultNonBigDecimals.length; i++) {
2385 Number n = nf.parse(defaultNonBigDecimals[i]);
2386 if (!(n instanceof BigDecimal)) {
2387 errln("FAIL: parse does not return BigDecimal instance");
2389 } catch (ParseException e) {
2390 errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
2393 // parse results for doubls must be always Double
2394 for (int i = 0; i < doubles.length; i++) {
2396 Number n = nf.parse(doubles[i]);
2397 if (!(n instanceof Double)) {
2398 errln("FAIL: parse does not return Double instance");
2400 } catch (ParseException e) {
2401 errln("parse of '" + doubles[i] + "' threw exception: " + e);
2406 public void TestNonpositiveMultiplier() {
2407 DecimalFormat df = new DecimalFormat("0");
2409 // test zero multiplier
2412 df.setMultiplier(0);
2415 errln("DecimalFormat.setMultiplier(0) did not throw an IllegalArgumentException");
2416 } catch (IllegalArgumentException ex) {
2420 // test negative multiplier
2423 df.setMultiplier(-1);
2425 if (df.getMultiplier() != -1) {
2426 errln("DecimalFormat.setMultiplier(-1) did not change the multiplier to -1");
2431 } catch (IllegalArgumentException ex) {
2433 errln("DecimalFormat.setMultiplier(-1) threw an IllegalArgumentException");
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);
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());
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());
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());
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();
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);
2467 for (int i = 0; i < numThreads; i++) {
2470 } catch (InterruptedException ie) {
2471 ie.printStackTrace();
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");
2480 errln("FAIL: " + errBuf);
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;
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;
2499 for (int i = 0; i < 10000; i++) {
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()));
2507 } catch (Throwable t) {
2508 synchronized(errors) {
2509 errors.add(new String(t.getClass().getName() + " - " + t.getMessage()));
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);
2529 * Testing the method public StringBuffer format(Object number, ...)
2531 public void TestFormat() {
2532 NumberFormat nf = NumberFormat.getInstance();
2533 StringBuffer sb = new StringBuffer("dummy");
2534 FieldPosition fp = new FieldPosition(0);
2536 // Tests when "if (number instanceof Long)" is true
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);
2544 // Tests when "else if (number instanceof BigInteger)" is true
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);
2552 // Tests when "else if (number instanceof java.math.BigDecimal)" is true
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);
2560 // Tests when "else if (number instanceof com.ibm.icu.math.BigDecimal)" is true
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);
2568 // Tests when "else if (number instanceof CurrencyAmount)" is true
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);
2577 // Tests when "else if (number instanceof Number)" is true
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);
2585 // Tests when "else" is true
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) {
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) {
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)
2605 public void TestGetInstance() {
2606 // Tests "public final static NumberFormat getInstance(int style)"
2608 int[] invalid_cases = { NumberFormat.NUMBERSTYLE - 1, NumberFormat.NUMBERSTYLE - 2,
2609 NumberFormat.PLURALCURRENCYSTYLE + 1, NumberFormat.PLURALCURRENCYSTYLE + 2 };
2611 for (int i = NumberFormat.NUMBERSTYLE; i < NumberFormat.PLURALCURRENCYSTYLE; i++) {
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);
2620 for (int i = 0; i < invalid_cases.length; i++) {
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) {
2629 // Tests "public static NumberFormat getInstance(Locale inLocale, int style)"
2630 String[] localeCases = { "en_US", "fr_FR", "de_DE", "jp_JP" };
2632 for (int i = NumberFormat.NUMBERSTYLE; i < NumberFormat.PLURALCURRENCYSTYLE; i++) {
2633 for (int j = 0; j < localeCases.length; j++) {
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);
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++) {
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) {
2656 * Tests the class public static abstract class NumberFormatFactory
2658 public void TestNumberFormatFactory() {
2660 * The following class allows the method public NumberFormat createFormat(Locale loc, int formatType) to be
2663 class TestFactory extends NumberFormatFactory {
2665 public Set<String> getSupportedLocaleNames() {
2670 public NumberFormat createFormat(ULocale loc, int formatType) {
2676 * The following class allows the method public NumberFormat createFormat(ULocale loc, int formatType) to be
2679 class TestFactory1 extends NumberFormatFactory {
2681 public Set<String> getSupportedLocaleNames() {
2686 public NumberFormat createFormat(Locale loc, int formatType) {
2691 TestFactory tf = new TestFactory();
2692 TestFactory1 tf1 = new TestFactory1();
2695 * Tests the method public boolean visible()
2697 if (tf.visible() != true) {
2698 errln("NumberFormatFactor.visible() was suppose to return true.");
2702 * Tests the method public NumberFormat createFormat(Locale loc, int formatType)
2704 if (tf.createFormat(new Locale(""), 0) != null) {
2705 errln("NumberFormatFactor.createFormat(Locale loc, int formatType) " + "was suppose to return null");
2709 * Tests the method public NumberFormat createFormat(ULocale loc, int formatType)
2711 if (tf1.createFormat(new ULocale(""), 0) != null) {
2712 errln("NumberFormatFactor.createFormat(ULocale loc, int formatType) " + "was suppose to return null");
2717 * Tests the class public static abstract class SimpleNumberFormatFactory extends NumberFormatFactory
2719 public void TestSimpleNumberFormatFactory() {
2720 class TestSimpleNumberFormatFactory extends SimpleNumberFormatFactory {
2722 * Tests the method public SimpleNumberFormatFactory(Locale locale)
2724 TestSimpleNumberFormatFactory() {
2725 super(new Locale(""));
2728 @SuppressWarnings("unused")
2729 TestSimpleNumberFormatFactory tsnff = new TestSimpleNumberFormatFactory();
2733 * Tests the method public static ULocale[] getAvailableLocales()
2735 @SuppressWarnings("static-access")
2736 public void TestGetAvailableLocales() {
2737 // Tests when "if (shim == null)" is true
2738 @SuppressWarnings("serial")
2739 class TestGetAvailableLocales extends NumberFormat {
2741 public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
2746 public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
2751 public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
2756 public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2761 public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2766 public Number parse(String text, ParsePosition parsePosition) {
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.");
2781 * Tests the method public void setMinimumIntegerDigits(int newValue)
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.");
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());
2806 * Tests the method public int getRoundingMode() public void setRoundingMode(int roundingMode)
2808 public void TestRoundingMode() {
2809 @SuppressWarnings("serial")
2810 class TestRoundingMode extends NumberFormat {
2812 public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
2817 public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
2822 public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
2827 public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2832 public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
2837 public Number parse(String text, ParsePosition parsePosition) {
2841 TestRoundingMode tgrm = new TestRoundingMode();
2843 // Tests the function 'public void setRoundingMode(int roundingMode)'
2845 tgrm.setRoundingMode(0);
2846 errln("NumberFormat.setRoundingMode(int) was suppose to return an exception");
2847 } catch (Exception e) {
2850 // Tests the function 'public int getRoundingMode()'
2852 tgrm.getRoundingMode();
2853 errln("NumberFormat.getRoundingMode() was suppose to return an exception");
2854 } catch (Exception e) {
2859 * Testing lenient decimal/grouping separator parsing
2861 public void TestLenientSymbolParsing() {
2862 DecimalFormat fmt = new DecimalFormat();
2863 DecimalFormatSymbols sym = new DecimalFormatSymbols();
2865 expect(fmt, "12\u300234", 12.34);
2867 // Ticket#7345 - case 1
2868 // Even strict parsing, the decimal separator set in the symbols
2869 // should be successfully parsed.
2871 sym.setDecimalSeparator('\u3002');
2874 fmt.setDecimalFormatSymbols(sym);
2876 // strict - failed before the fix for #7345
2877 fmt.setParseStrict(true);
2878 expect(fmt, "23\u300245", 23.45);
2879 fmt.setParseStrict(false);
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);
2889 expect(fmt, "1,234.56", 1234.56);
2891 sym.setGroupingSeparator('\uFF61');
2892 fmt.setDecimalFormatSymbols(sym);
2894 expect(fmt, "2\uFF61345.67", 2345.67);
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);
2905 expect(fmt, "12 345", 12345);
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");
2912 expect(fmt, "23 456", 23);
2914 // Set the configuration back to the default
2915 System.setProperty("com.ibm.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false");
2919 * Testing currency driven max/min fraction digits problem
2920 * reported by ticket#7282
2922 public void TestCurrencyFractionDigits() {
2923 double value = 99.12345;
2925 // Create currency instance
2926 NumberFormat cfmt = NumberFormat.getCurrencyInstance(new ULocale("ja_JP"));
2927 String text1 = cfmt.format(value);
2929 // Reset the same currency and format the test value again
2930 cfmt.setCurrency(cfmt.getCurrency());
2931 String text2 = cfmt.format(value);
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);
2941 * Testing rounding to negative zero problem
2942 * reported by ticket#7609
2944 public void TestNegZeroRounding() {
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);
2952 df.setRoundingIncrement(0.1);
2953 String text2 = df.format(-0.01);
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);
2963 public void TestCurrencyAmountCoverage() {
2964 CurrencyAmount ca, cb;
2967 ca = new CurrencyAmount(null, null);
2968 errln("NullPointerException should have been thrown.");
2969 } catch (NullPointerException ex) {
2972 ca = new CurrencyAmount(new Integer(0), null);
2973 errln("NullPointerException should have been thrown.");
2974 } catch (NullPointerException ex) {
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.");
2982 if (!ca.equals(ca)) {
2983 errln("Comparision should return true.");
2985 if (ca.equals(cb)) {
2986 errln("Comparison should return false.");
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());
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
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",
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);
3021 errln("FAIL: 1250.75 x " + locale + " => " + s +
3022 ", expected " + DATA[i+3]);
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.
3034 public void TestFormatToCharacterIteratorThread() {
3035 final int COUNT = 10;
3037 DecimalFormat fmt1 = new DecimalFormat("#0");
3038 DecimalFormat fmt2 = (DecimalFormat)fmt1.clone();
3040 int[] res1 = new int[COUNT];
3041 int[] res2 = new int[COUNT];
3043 Thread t1 = new Thread(new FormatCharItrTestThread(fmt1, 1, res1));
3044 Thread t2 = new Thread(new FormatCharItrTestThread(fmt2, 100, res2));
3052 } catch (InterruptedException e) {
3059 for (int i = 0; i < COUNT; i++) {
3060 if (res1[i] != val1) {
3061 errln("Inconsistent first run limit in test thread 1");
3063 if (res2[i] != val2) {
3064 errln("Inconsistent first run limit in test thread 2");
3069 public void TestParseMaxDigits() {
3070 DecimalFormat fmt = new DecimalFormat();
3071 String number = "100000000000";
3072 int newParseMax = number.length() - 1;
3074 fmt.setParseMaxDigits(-1);
3076 /* Default value is 1000 */
3077 if (fmt.getParseMaxDigits() != 1000) {
3078 errln("Fail valid value checking in setParseMaxDigits.");
3082 if (fmt.parse(number).doubleValue() == Float.POSITIVE_INFINITY) {
3083 errln("Got Infinity but should NOT when parsing number: " + number);
3086 fmt.setParseMaxDigits(newParseMax);
3088 if (fmt.parse(number).doubleValue() != Float.POSITIVE_INFINITY) {
3089 errln("Did not get Infinity but should when parsing number: " + number);
3091 } catch (ParseException ex) {
3096 private static class FormatCharItrTestThread implements Runnable {
3097 private final NumberFormat fmt;
3098 private final int num;
3099 private final int[] result;
3101 FormatCharItrTestThread(NumberFormat fmt, int num, int[] result) {
3104 this.result = result;
3108 for (int i = 0; i < result.length; i++) {
3109 AttributedCharacterIterator acitr = fmt.formatToCharacterIterator(num);
3111 result[i] = acitr.getRunLimit();
3116 public void TestRoundingBehavior() {
3117 final Object[][] TEST_CASES = {
3119 ULocale.US, // ULocale - null for default locale
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
3130 Double.valueOf(0.1d),
3131 Double.valueOf(123.4567d),
3137 Integer.valueOf(BigDecimal.ROUND_DOWN),
3138 Double.valueOf(0.1d),
3139 Double.valueOf(123.4567d),
3145 Integer.valueOf(BigDecimal.ROUND_UNNECESSARY),
3147 Double.valueOf(123.4567d),
3153 Integer.valueOf(BigDecimal.ROUND_DOWN),
3162 for (Object[] testCase : TEST_CASES) {
3165 ULocale locale = testCase[0] == null ? ULocale.getDefault() : (ULocale)testCase[0];
3166 String pattern = (String)testCase[1];
3168 DecimalFormat fmt = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(locale));
3171 Integer roundingMode = null;
3172 if (testCase[2] != null) {
3173 roundingMode = (Integer)testCase[2];
3174 fmt.setRoundingMode(roundingMode);
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]);
3190 boolean bException = false;
3192 s = fmt.format(testCase[4]);
3193 } catch (ArithmeticException e) {
3198 if (testCase[5] != null) {
3199 errln("Test case #" + testNum + ": ArithmeticException was thrown.");
3202 if (testCase[5] == null) {
3203 errln("Test case #" + testNum +
3204 ": ArithmeticException must be thrown, but got formatted result: " +
3207 assertEquals("Test case #" + testNum, (String)testCase[5], s);
3215 public void TestSignificantDigits() {
3221 123.44501, -123.44501,
3222 0.001234, -0.001234,
3223 0.00000000123, -0.00000000123,
3224 0.0000000000000000000123, -0.0000000000000000000123,
3226 0.0000000012344501, -0.0000000012344501,
3227 123445.01, -123445.01,
3228 12344501000000000000000000000000000.0, -12344501000000000000000000000000000.0,
3230 String[] expected = {
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",
3240 "0.0000000012345", "-0.0000000012345",
3241 "123450", "-123450",
3242 "12345000000000000000000000000000000", "-12345000000000000000000000000000000",
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]));
3255 public void TestBug9936() {
3256 DecimalFormat numberFormat =
3257 (DecimalFormat) NumberFormat.getInstance(ULocale.US);
3258 assertFalse("", numberFormat.areSignificantDigitsUsed());
3260 numberFormat.setSignificantDigitsUsed(true);
3261 assertTrue("", numberFormat.areSignificantDigitsUsed());
3263 numberFormat.setSignificantDigitsUsed(false);
3264 assertFalse("", numberFormat.areSignificantDigitsUsed());
3266 numberFormat.setMinimumSignificantDigits(3);
3267 assertTrue("", numberFormat.areSignificantDigitsUsed());
3269 numberFormat.setSignificantDigitsUsed(false);
3270 numberFormat.setMaximumSignificantDigits(6);
3271 assertTrue("", numberFormat.areSignificantDigitsUsed());
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));
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 российских рублей"},
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);
3315 public void TestCustomCurrencySignAndSeparator() {
3316 DecimalFormatSymbols custom = new DecimalFormatSymbols(ULocale.US);
3318 custom.setCurrencySymbol("*");
3319 custom.setMonetaryGroupingSeparator('^');
3320 custom.setMonetaryDecimalSeparator(':');
3322 DecimalFormat fmt = new DecimalFormat("\u00A4 #,##0.00", custom);
3324 final String numstr = "* 1^234:56";
3325 expect2(fmt, 1234.56, numstr);
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) {
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).
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 ), // ***
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 ), // ***
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 ), // ***
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 ), // ***
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 ), // ***
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 ), // ***
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 ), // ***
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 ), // ***
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);
3437 errln("FAIL: locale " + item.locale + ", lenient " + item.lenient + ", parse of \"" + item.numString + "\" gives position " + ppos.getIndex());
3440 errln("FAIL: NumberFormat.getInstance for locale " + item.locale);