1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 2001-2016, International Business Machines Corporation and
7 * others. All Rights Reserved.
8 *******************************************************************************
9 */
10
11/**
12 * Port From:   ICU4C v1.8.1 : format : NumberFormatTest
13 * Source File: $ICU4oot/source/test/intltest/numfmtst.cpp
14 **/
15
16package android.icu.dev.test.format;
17
18import java.io.IOException;
19import java.math.BigInteger;
20import java.text.AttributedCharacterIterator;
21import java.text.FieldPosition;
22import java.text.Format;
23import java.text.ParseException;
24import java.text.ParsePosition;
25import java.util.ArrayList;
26import java.util.Iterator;
27import java.util.List;
28import java.util.Locale;
29import java.util.Set;
30
31import org.junit.Test;
32
33import android.icu.dev.test.TestFmwk;
34import android.icu.dev.test.TestUtil;
35import android.icu.dev.test.format.IntlTestDecimalFormatAPIC.FieldContainer;
36import android.icu.impl.ICUConfig;
37import android.icu.impl.LocaleUtility;
38import android.icu.impl.data.ResourceReader;
39import android.icu.impl.data.TokenIterator;
40import android.icu.math.BigDecimal;
41import android.icu.math.MathContext;
42import android.icu.text.CompactDecimalFormat;
43import android.icu.text.DecimalFormat;
44import android.icu.text.DecimalFormatSymbols;
45import android.icu.text.DisplayContext;
46import android.icu.text.MeasureFormat;
47import android.icu.text.NumberFormat;
48import android.icu.text.NumberFormat.NumberFormatFactory;
49import android.icu.text.NumberFormat.SimpleNumberFormatFactory;
50import android.icu.text.NumberingSystem;
51import android.icu.text.RuleBasedNumberFormat;
52import android.icu.util.Currency;
53import android.icu.util.CurrencyAmount;
54import android.icu.util.ULocale;
55
56public class NumberFormatTest extends TestFmwk {
57
58    private static ULocale EN = new ULocale("en");
59
60    private static Number toNumber(String s) {
61        if (s.equals("NaN")) {
62            return Double.NaN;
63        } else if (s.equals("-Inf")) {
64            return Double.NEGATIVE_INFINITY;
65        } else if (s.equals("Inf")) {
66            return Double.POSITIVE_INFINITY;
67        }
68        return new BigDecimal(s);
69    }
70
71
72    private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU =
73            new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
74                @Override
75                public Character Id() { return 'J'; }
76
77                @Override
78                public String format(NumberFormatTestData tuple) {
79                    DecimalFormat fmt = newDecimalFormat(tuple);
80                    String actual = fmt.format(toNumber(tuple.format));
81                    String expected = tuple.output;
82                    if (!expected.equals(actual)) {
83                        return "Expected " + expected + ", got " + actual;
84                    }
85                    return null;
86                }
87
88                @Override
89                public String toPattern(NumberFormatTestData tuple) {
90                    DecimalFormat fmt = newDecimalFormat(tuple);
91                    StringBuilder result = new StringBuilder();
92                    if (tuple.toPattern != null) {
93                        String expected = tuple.toPattern;
94                        String actual = fmt.toPattern();
95                        if (!expected.equals(actual)) {
96                            result.append("Expected toPattern=" + expected + ", got " + actual);
97                        }
98                    }
99                    if (tuple.toLocalizedPattern != null) {
100                        String expected = tuple.toLocalizedPattern;
101                        String actual = fmt.toLocalizedPattern();
102                        if (!expected.equals(actual)) {
103                            result.append("Expected toLocalizedPattern=" + expected + ", got " + actual);
104                        }
105                    }
106                    return result.length() == 0 ? null : result.toString();
107                }
108
109                @Override
110                public String parse(NumberFormatTestData tuple) {
111                    DecimalFormat fmt = newDecimalFormat(tuple);
112                    ParsePosition ppos = new ParsePosition(0);
113                    Number actual = fmt.parse(tuple.parse, ppos);
114                    if (ppos.getIndex() == 0) {
115                        if (!tuple.output.equals("fail")) {
116                            return "Parse error expected.";
117                        }
118                        return null;
119                    }
120                    if (tuple.output.equals("fail")) {
121                        return "Parse succeeded: "+actual+", but was expected to fail.";
122                    }
123                    Number expected = toNumber(tuple.output);
124                    // number types cannot be compared, this is the best we can do.
125                    if (expected.doubleValue() != (actual.doubleValue())) {
126                        return "Expected: " + expected + ", got: " + actual;
127                    }
128                    return null;
129                }
130
131                @Override
132                public String parseCurrency(NumberFormatTestData tuple) {
133                    DecimalFormat fmt = newDecimalFormat(tuple);
134                    ParsePosition ppos = new ParsePosition(0);
135                    CurrencyAmount currAmt = fmt.parseCurrency(tuple.parse, ppos);
136                    if (ppos.getIndex() == 0) {
137                        if (!tuple.output.equals("fail")) {
138                            return "Parse error expected.";
139                        }
140                        return null;
141                    }
142                    if (tuple.output.equals("fail")) {
143                        return "Parse succeeded: "+currAmt+", but was expected to fail.";
144                    }
145                    Number expected = toNumber(tuple.output);
146                    Number actual = currAmt.getNumber();
147                    // number types cannot be compared, this is the best we can do.
148                    if (expected.doubleValue() != (actual.doubleValue())) {
149                        return "Expected: " + expected + ", got: " + actual;
150                    }
151
152                    if (!tuple.outputCurrency.equals(currAmt.getCurrency().toString())) {
153                        return "Expected currency: " + tuple.outputCurrency + ", got: " + currAmt.getCurrency();
154                    }
155                    return null;
156                }
157
158                /**
159                 * @param tuple
160                 * @return
161                 */
162                private DecimalFormat newDecimalFormat(NumberFormatTestData tuple) {
163
164                    DecimalFormat fmt = new DecimalFormat(
165                            tuple.pattern == null ? "0" : tuple.pattern,
166                            new DecimalFormatSymbols(tuple.locale == null ? EN : tuple.locale));
167                    adjustDecimalFormat(tuple, fmt);
168                    return fmt;
169                }
170                /**
171                 * @param tuple
172                 * @param fmt
173                 */
174                private void adjustDecimalFormat(NumberFormatTestData tuple, DecimalFormat fmt) {
175                    if (tuple.minIntegerDigits != null) {
176                        fmt.setMinimumIntegerDigits(tuple.minIntegerDigits);
177                    }
178                    if (tuple.maxIntegerDigits != null) {
179                        fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits);
180                    }
181                    if (tuple.minFractionDigits != null) {
182                        fmt.setMinimumFractionDigits(tuple.minFractionDigits);
183                    }
184                    if (tuple.maxFractionDigits != null) {
185                        fmt.setMaximumFractionDigits(tuple.maxFractionDigits);
186                    }
187                    if (tuple.currency != null) {
188                        fmt.setCurrency(tuple.currency);
189                    }
190                    if (tuple.minGroupingDigits != null) {
191                        // Oops we don't support this.
192                    }
193                    if (tuple.useSigDigits != null) {
194                        fmt.setSignificantDigitsUsed(
195                                tuple.useSigDigits != 0);
196                    }
197                    if (tuple.minSigDigits != null) {
198                        fmt.setMinimumSignificantDigits(tuple.minSigDigits);
199                    }
200                    if (tuple.maxSigDigits != null) {
201                        fmt.setMaximumSignificantDigits(tuple.maxSigDigits);
202                    }
203                    if (tuple.useGrouping != null) {
204                        fmt.setGroupingUsed(tuple.useGrouping != 0);
205                    }
206                    if (tuple.multiplier != null) {
207                        fmt.setMultiplier(tuple.multiplier);
208                    }
209                    if (tuple.roundingIncrement != null) {
210                        fmt.setRoundingIncrement(tuple.roundingIncrement.doubleValue());
211                    }
212                    if (tuple.formatWidth != null) {
213                        fmt.setFormatWidth(tuple.formatWidth);
214                    }
215                    if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
216                        fmt.setPadCharacter(tuple.padCharacter.charAt(0));
217                    }
218                    if (tuple.useScientific != null) {
219                        fmt.setScientificNotation(tuple.useScientific != 0);
220                    }
221                    if (tuple.grouping != null) {
222                        fmt.setGroupingSize(tuple.grouping);
223                    }
224                    if (tuple.grouping2 != null) {
225                        fmt.setSecondaryGroupingSize(tuple.grouping2);
226                    }
227                    if (tuple.roundingMode != null) {
228                        fmt.setRoundingMode(tuple.roundingMode);
229                    }
230                    if (tuple.currencyUsage != null) {
231                        fmt.setCurrencyUsage(tuple.currencyUsage);
232                    }                    if (tuple.minimumExponentDigits != null) {
233                        fmt.setMinimumExponentDigits(
234                                tuple.minimumExponentDigits.byteValue());
235                    }
236                    if (tuple.exponentSignAlwaysShown != null) {
237                        fmt.setExponentSignAlwaysShown(
238                                tuple.exponentSignAlwaysShown != 0);
239                    }
240                    if (tuple.decimalSeparatorAlwaysShown != null) {
241                        fmt.setDecimalSeparatorAlwaysShown(
242                                tuple.decimalSeparatorAlwaysShown != 0);
243                    }
244                    if (tuple.padPosition != null) {
245                        fmt.setPadPosition(tuple.padPosition);
246                    }
247                    if (tuple.positivePrefix != null) {
248                        fmt.setPositivePrefix(tuple.positivePrefix);
249                    }
250                    if (tuple.positiveSuffix != null) {
251                        fmt.setPositiveSuffix(tuple.positiveSuffix);
252                    }
253                    if (tuple.negativePrefix != null) {
254                        fmt.setNegativePrefix(tuple.negativePrefix);
255                    }
256                    if (tuple.negativeSuffix != null) {
257                        fmt.setNegativeSuffix(tuple.negativeSuffix);
258                    }
259                    if (tuple.localizedPattern != null) {
260                        fmt.applyLocalizedPattern(tuple.localizedPattern);
261                    }
262                    int lenient = tuple.lenient == null ? 1 : tuple.lenient.intValue();
263                    fmt.setParseStrict(lenient == 0);
264                    if (tuple.parseIntegerOnly != null) {
265                        fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
266                    }
267                    if (tuple.decimalPatternMatchRequired != null) {
268                        fmt.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0);
269                    }
270                    if (tuple.parseNoExponent != null) {
271                        // Oops, not supported for now
272                    }
273                }
274    };
275
276
277    private DataDrivenNumberFormatTestUtility.CodeUnderTest JDK =
278            new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
279                @Override
280                public Character Id() { return 'K'; }
281
282                @Override
283                public String format(NumberFormatTestData tuple) {
284                    java.text.DecimalFormat fmt = newDecimalFormat(tuple);
285                    String actual = fmt.format(toNumber(tuple.format));
286                    String expected = tuple.output;
287                    if (!expected.equals(actual)) {
288                        return "Expected " + expected + ", got " + actual;
289                    }
290                    return null;
291                }
292
293                @Override
294                public String toPattern(NumberFormatTestData tuple) {
295                    java.text.DecimalFormat fmt = newDecimalFormat(tuple);
296                    StringBuilder result = new StringBuilder();
297                    if (tuple.toPattern != null) {
298                        String expected = tuple.toPattern;
299                        String actual = fmt.toPattern();
300                        if (!expected.equals(actual)) {
301                            result.append("Expected toPattern=" + expected + ", got " + actual);
302                        }
303                    }
304                    if (tuple.toLocalizedPattern != null) {
305                        String expected = tuple.toLocalizedPattern;
306                        String actual = fmt.toLocalizedPattern();
307                        if (!expected.equals(actual)) {
308                            result.append("Expected toLocalizedPattern=" + expected + ", got " + actual);
309                        }
310                    }
311                    return result.length() == 0 ? null : result.toString();
312                }
313
314                @Override
315                public String parse(NumberFormatTestData tuple) {
316                    java.text.DecimalFormat fmt = newDecimalFormat(tuple);
317                    ParsePosition ppos = new ParsePosition(0);
318                    Number actual = fmt.parse(tuple.parse, ppos);
319                    if (ppos.getIndex() == 0) {
320                        if (!tuple.output.equals("fail")) {
321                            return "Parse error expected.";
322                        }
323                        return null;
324                    }
325                    if (tuple.output.equals("fail")) {
326                        return "Parse succeeded: "+actual+", but was expected to fail.";
327                    }
328                    Number expected = toNumber(tuple.output);
329                    // number types cannot be compared, this is the best we can do.
330                    if (expected.doubleValue() != actual.doubleValue()) {
331                        return "Expected: " + expected + ", got: " + actual;
332                    }
333                    return null;
334                }
335
336
337
338                /**
339                 * @param tuple
340                 * @return
341                 */
342                private java.text.DecimalFormat newDecimalFormat(NumberFormatTestData tuple) {
343                    java.text.DecimalFormat fmt = new java.text.DecimalFormat(
344                            tuple.pattern == null ? "0" : tuple.pattern,
345                            new java.text.DecimalFormatSymbols(
346                                    (tuple.locale == null ? EN : tuple.locale).toLocale()));
347                    adjustDecimalFormat(tuple, fmt);
348                    return fmt;
349                }
350
351                /**
352                 * @param tuple
353                 * @param fmt
354                 */
355                private void adjustDecimalFormat(NumberFormatTestData tuple, java.text.DecimalFormat fmt) {
356                    if (tuple.minIntegerDigits != null) {
357                        fmt.setMinimumIntegerDigits(tuple.minIntegerDigits);
358                    }
359                    if (tuple.maxIntegerDigits != null) {
360                        fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits);
361                    }
362                    if (tuple.minFractionDigits != null) {
363                        fmt.setMinimumFractionDigits(tuple.minFractionDigits);
364                    }
365                    if (tuple.maxFractionDigits != null) {
366                        fmt.setMaximumFractionDigits(tuple.maxFractionDigits);
367                    }
368                    if (tuple.currency != null) {
369                        fmt.setCurrency(java.util.Currency.getInstance(tuple.currency.toString()));
370                    }
371                    if (tuple.minGroupingDigits != null) {
372                        // Oops we don't support this.
373                    }
374                    if (tuple.useSigDigits != null) {
375                        // Oops we don't support this
376                    }
377                    if (tuple.minSigDigits != null) {
378                        // Oops we don't support this
379                    }
380                    if (tuple.maxSigDigits != null) {
381                        // Oops we don't support this
382                    }
383                    if (tuple.useGrouping != null) {
384                        fmt.setGroupingUsed(tuple.useGrouping != 0);
385                    }
386                    if (tuple.multiplier != null) {
387                        fmt.setMultiplier(tuple.multiplier);
388                    }
389                    if (tuple.roundingIncrement != null) {
390                        // Not supported
391                    }
392                    if (tuple.formatWidth != null) {
393                        // Not supported
394                    }
395                    if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
396                        // Not supported
397                    }
398                    if (tuple.useScientific != null) {
399                        // Not supported
400                    }
401                    if (tuple.grouping != null) {
402                        fmt.setGroupingSize(tuple.grouping);
403                    }
404                    if (tuple.grouping2 != null) {
405                        // Not supported
406                    }
407                    if (tuple.roundingMode != null) {
408                        // Not supported
409                    }
410                    if (tuple.currencyUsage != null) {
411                        // Not supported
412                    }
413                    if (tuple.minimumExponentDigits != null) {
414                        // Not supported
415                    }
416                    if (tuple.exponentSignAlwaysShown != null) {
417                        // Not supported
418                    }
419                    if (tuple.decimalSeparatorAlwaysShown != null) {
420                        fmt.setDecimalSeparatorAlwaysShown(
421                                tuple.decimalSeparatorAlwaysShown != 0);
422                    }
423                    if (tuple.padPosition != null) {
424                        // Not supported
425                    }
426                    if (tuple.positivePrefix != null) {
427                        fmt.setPositivePrefix(tuple.positivePrefix);
428                    }
429                    if (tuple.positiveSuffix != null) {
430                        fmt.setPositiveSuffix(tuple.positiveSuffix);
431                    }
432                    if (tuple.negativePrefix != null) {
433                        fmt.setNegativePrefix(tuple.negativePrefix);
434                    }
435                    if (tuple.negativeSuffix != null) {
436                        fmt.setNegativeSuffix(tuple.negativeSuffix);
437                    }
438                    if (tuple.localizedPattern != null) {
439                        fmt.applyLocalizedPattern(tuple.localizedPattern);
440                    }
441
442                    // lenient parsing not supported by JDK
443                    if (tuple.parseIntegerOnly != null) {
444                        fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
445                    }
446                    if (tuple.decimalPatternMatchRequired != null) {
447                       // Oops, not supported
448                    }
449                    if (tuple.parseNoExponent != null) {
450                        // Oops, not supported for now
451                    }
452                }
453    };
454
455    @Test
456    public void TestRoundingScientific10542() {
457        DecimalFormat format =
458                new DecimalFormat("0.00E0");
459
460        int[] roundingModes = {
461              BigDecimal.ROUND_CEILING,
462              BigDecimal.ROUND_DOWN,
463              BigDecimal.ROUND_FLOOR,
464              BigDecimal.ROUND_HALF_DOWN,
465              BigDecimal.ROUND_HALF_EVEN,
466              BigDecimal.ROUND_HALF_UP,
467              BigDecimal.ROUND_UP};
468        String[] descriptions = {
469                "Round Ceiling",
470                "Round Down",
471                "Round Floor",
472                "Round half down",
473                "Round half even",
474                "Round half up",
475                "Round up"};
476
477        double[] values = {-0.003006, -0.003005, -0.003004, 0.003014, 0.003015, 0.003016};
478        // The order of these expected values correspond to the order of roundingModes and the order of values.
479        String[][] expected = {
480                {"-3.00E-3", "-3.00E-3", "-3.00E-3", "3.02E-3", "3.02E-3", "3.02E-3"},
481                {"-3.00E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.01E-3"},
482                {"-3.01E-3", "-3.01E-3", "-3.01E-3", "3.01E-3", "3.01E-3", "3.01E-3"},
483                {"-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.02E-3"},
484                {"-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3"},
485                {"-3.01E-3", "-3.01E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3"},
486                {"-3.01E-3", "-3.01E-3", "-3.01E-3", "3.02E-3", "3.02E-3", "3.02E-3"}};
487        verifyRounding(format, values, expected, roundingModes, descriptions);
488        values = new double[]{-3006.0, -3005, -3004, 3014, 3015, 3016};
489        // The order of these expected values correspond to the order of roundingModes and the order of values.
490        expected = new String[][]{
491                {"-3.00E3", "-3.00E3", "-3.00E3", "3.02E3", "3.02E3", "3.02E3"},
492                {"-3.00E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.01E3"},
493                {"-3.01E3", "-3.01E3", "-3.01E3", "3.01E3", "3.01E3", "3.01E3"},
494                {"-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.02E3"},
495                {"-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3"},
496                {"-3.01E3", "-3.01E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3"},
497                {"-3.01E3", "-3.01E3", "-3.01E3", "3.02E3", "3.02E3", "3.02E3"}};
498        verifyRounding(format, values, expected, roundingModes, descriptions);
499        values = new double[]{0.0, -0.0};
500        // The order of these expected values correspond to the order of roundingModes and the order of values.
501        expected = new String[][]{
502                {"0.00E0", "-0.00E0"},
503                {"0.00E0", "-0.00E0"},
504                {"0.00E0", "-0.00E0"},
505                {"0.00E0", "-0.00E0"},
506                {"0.00E0", "-0.00E0"},
507                {"0.00E0", "-0.00E0"},
508                {"0.00E0", "-0.00E0"}};
509        verifyRounding(format, values, expected, roundingModes, descriptions);
510        values = new double[]{1e25, 1e25 + 1e15, 1e25 - 1e15};
511        // The order of these expected values correspond to the order of roundingModes and the order of values.
512        expected = new String[][]{
513                {"1.00E25", "1.01E25", "1.00E25"},
514                {"1.00E25", "1.00E25", "9.99E24"},
515                {"1.00E25", "1.00E25", "9.99E24"},
516                {"1.00E25", "1.00E25", "1.00E25"},
517                {"1.00E25", "1.00E25", "1.00E25"},
518                {"1.00E25", "1.00E25", "1.00E25"},
519                {"1.00E25", "1.01E25", "1.00E25"}};
520        verifyRounding(format, values, expected, roundingModes, descriptions);
521        values = new double[]{-1e25, -1e25 + 1e15, -1e25 - 1e15};
522        // The order of these expected values correspond to the order of roundingModes and the order of values.
523        expected = new String[][]{
524                {"-1.00E25", "-9.99E24", "-1.00E25"},
525                {"-1.00E25", "-9.99E24", "-1.00E25"},
526                {"-1.00E25", "-1.00E25", "-1.01E25"},
527                {"-1.00E25", "-1.00E25", "-1.00E25"},
528                {"-1.00E25", "-1.00E25", "-1.00E25"},
529                {"-1.00E25", "-1.00E25", "-1.00E25"},
530                {"-1.00E25", "-1.00E25", "-1.01E25"}};
531        verifyRounding(format, values, expected, roundingModes, descriptions);
532        values = new double[]{1e-25, 1e-25 + 1e-35, 1e-25 - 1e-35};
533        // The order of these expected values correspond to the order of roundingModes and the order of values.
534        expected = new String[][]{
535                {"1.00E-25", "1.01E-25", "1.00E-25"},
536                {"1.00E-25", "1.00E-25", "9.99E-26"},
537                {"1.00E-25", "1.00E-25", "9.99E-26"},
538                {"1.00E-25", "1.00E-25", "1.00E-25"},
539                {"1.00E-25", "1.00E-25", "1.00E-25"},
540                {"1.00E-25", "1.00E-25", "1.00E-25"},
541                {"1.00E-25", "1.01E-25", "1.00E-25"}};
542        verifyRounding(format, values, expected, roundingModes, descriptions);
543        values = new double[]{-1e-25, -1e-25 + 1e-35, -1e-25 - 1e-35};
544        // The order of these expected values correspond to the order of roundingModes and the order of values.
545        expected = new String[][]{
546                {"-1.00E-25", "-9.99E-26", "-1.00E-25"},
547                {"-1.00E-25", "-9.99E-26", "-1.00E-25"},
548                {"-1.00E-25", "-1.00E-25", "-1.01E-25"},
549                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
550                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
551                {"-1.00E-25", "-1.00E-25", "-1.00E-25"},
552                {"-1.00E-25", "-1.00E-25", "-1.01E-25"}};
553        verifyRounding(format, values, expected, roundingModes, descriptions);
554    }
555
556    private void verifyRounding(DecimalFormat format, double[] values, String[][] expected, int[] roundingModes,
557            String[] descriptions) {
558        for (int i = 0; i < roundingModes.length; i++) {
559            format.setRoundingMode(roundingModes[i]);
560            for (int j = 0; j < values.length; j++) {
561                assertEquals(descriptions[i]+" " +values[j], expected[i][j], format.format(values[j]));
562            }
563        }
564    }
565
566    @Test
567    public void Test10419RoundingWith0FractionDigits() {
568        Object[][] data = new Object[][]{
569                {BigDecimal.ROUND_CEILING, 1.488, "2"},
570                {BigDecimal.ROUND_DOWN, 1.588, "1"},
571                {BigDecimal.ROUND_FLOOR, 1.588, "1"},
572                {BigDecimal.ROUND_HALF_DOWN, 1.5, "1"},
573                {BigDecimal.ROUND_HALF_EVEN, 2.5, "2"},
574                {BigDecimal.ROUND_HALF_UP, 2.5, "3"},
575                {BigDecimal.ROUND_UP, 1.5, "2"},
576        };
577        NumberFormat nff = NumberFormat.getNumberInstance(ULocale.ENGLISH);
578        nff.setMaximumFractionDigits(0);
579        for (Object[] item : data) {
580          nff.setRoundingMode(((Integer) item[0]).intValue());
581          assertEquals("Test10419", item[2], nff.format(item[1]));
582        }
583    }
584
585    @Test
586    public void TestParseNegativeWithFaLocale() {
587        DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("fa"));
588        try {
589            double value = parser.parse("-0,5").doubleValue();
590            assertEquals("Expect -0.5", -0.5, value);
591        } catch (ParseException e) {
592            TestFmwk.errln("Parsing -0.5 should have succeeded.");
593        }
594    }
595
596    @Test
597    public void TestParseNegativeWithAlternativeMinusSign() {
598        DecimalFormat parser = (DecimalFormat) NumberFormat.getInstance(new ULocale("en"));
599        try {
600            double value = parser.parse("\u208B0.5").doubleValue();
601            assertEquals("Expect -0.5", -0.5, value);
602        } catch (ParseException e) {
603            TestFmwk.errln("Parsing -0.5 should have succeeded.");
604        }
605    }
606
607    // Test various patterns
608    @Test
609    public void TestPatterns() {
610
611        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
612        final String pat[]    = { "#.#", "#.", ".#", "#" };
613        int pat_length = pat.length;
614        final String newpat[] = { "#0.#", "#0.", "#.0", "#" };
615        final String num[]    = { "0",   "0.", ".0", "0" };
616        for (int i=0; i<pat_length; ++i)
617        {
618            DecimalFormat fmt = new DecimalFormat(pat[i], sym);
619            String newp = fmt.toPattern();
620            if (!newp.equals(newpat[i]))
621                errln("FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
622                        "; " + newp + " seen instead");
623
624            String s = ((NumberFormat)fmt).format(0);
625            if (!s.equals(num[i]))
626            {
627                errln("FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
628                        "; " + s + " seen instead");
629                logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
630            }
631            // BigInteger 0 - ticket#4731
632            s = ((NumberFormat)fmt).format(BigInteger.ZERO);
633            if (!s.equals(num[i]))
634            {
635                errln("FAIL: Pattern " + pat[i] + " should format BigInteger zero as " + num[i] +
636                        "; " + s + " seen instead");
637                logln("Min integer digits = " + fmt.getMinimumIntegerDigits());
638            }
639        }
640    }
641
642    // Test exponential pattern
643    @Test
644    public void TestExponential() {
645
646        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
647        final String pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
648        int pat_length = pat.length;
649
650        double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
651        int val_length = val.length;
652        final String valFormat[] = {
653                // 0.####E0
654                "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
655                // 00.000E00
656                "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
657                // ##0.######E000
658                "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
659                // 0.###E0;[0.###E0]
660                "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" };
661        /*double valParse[] =
662            {
663                0.01234, 123460000, 1.23E300, -3.1416E-271,
664                0.01234, 123460000, 1.23E300, -3.1416E-271,
665                0.01234, 123456800, 1.23E300, -3.141593E-271,
666                0.01234, 123500000, 1.23E300, -3.142E-271,
667            };*/ //The variable is never used
668
669        int lval[] = { 0, -1, 1, 123456789 };
670        int lval_length = lval.length;
671        final String lvalFormat[] = {
672                // 0.####E0
673                "0E0", "-1E0", "1E0", "1.2346E8",
674                // 00.000E00
675                "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
676                // ##0.######E000
677                "0E000", "-1E000", "1E000", "123.4568E006",
678                // 0.###E0;[0.###E0]
679                "0E0", "[1E0]", "1E0", "1.235E8" };
680        int lvalParse[] =
681            {
682                0, -1, 1, 123460000,
683                0, -1, 1, 123460000,
684                0, -1, 1, 123456800,
685                0, -1, 1, 123500000,
686            };
687        int ival = 0, ilval = 0;
688        for (int p = 0; p < pat_length; ++p) {
689            DecimalFormat fmt = new DecimalFormat(pat[p], sym);
690            logln("Pattern \"" + pat[p] + "\" -toPattern-> \"" + fmt.toPattern() + "\"");
691            int v;
692            for (v = 0; v < val_length; ++v) {
693                String s;
694                s = ((NumberFormat) fmt).format(val[v]);
695                logln(" " + val[v] + " -format-> " + s);
696                if (!s.equals(valFormat[v + ival]))
697                    errln("FAIL: Expected " + valFormat[v + ival]);
698
699                ParsePosition pos = new ParsePosition(0);
700                double a = fmt.parse(s, pos).doubleValue();
701                if (pos.getIndex() == s.length()) {
702                    logln("  -parse-> " + Double.toString(a));
703                    // Use epsilon comparison as necessary
704                } else
705                    errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
706            }
707            for (v = 0; v < lval_length; ++v) {
708                String s;
709                s = ((NumberFormat) fmt).format(lval[v]);
710                logln(" " + lval[v] + "L -format-> " + s);
711                if (!s.equals(lvalFormat[v + ilval]))
712                    errln("ERROR: Expected " + lvalFormat[v + ilval] + " Got: " + s);
713
714                ParsePosition pos = new ParsePosition(0);
715                long a = 0;
716                Number A = fmt.parse(s, pos);
717                if (A != null) {
718                    a = A.longValue();
719                    if (pos.getIndex() == s.length()) {
720                        logln("  -parse-> " + a);
721                        if (a != lvalParse[v + ilval])
722                            errln("FAIL: Expected " + lvalParse[v + ilval]);
723                    } else
724                        errln("FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + Long.toString(a));
725                } else {
726                    errln("Fail to parse the string: " + s);
727                }
728            }
729            ival += val_length;
730            ilval += lval_length;
731        }
732    }
733
734    // Test the handling of quotes
735    @Test
736    public void TestQuotes() {
737
738        StringBuffer pat;
739        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
740        pat = new StringBuffer("a'fo''o'b#");
741        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
742        String s = ((NumberFormat)fmt).format(123);
743        logln("Pattern \"" + pat + "\"");
744        logln(" Format 123 . " + s);
745        if (!s.equals("afo'ob123"))
746            errln("FAIL: Expected afo'ob123");
747
748        s ="";
749        pat = new StringBuffer("a''b#");
750        fmt = new DecimalFormat(pat.toString(), sym);
751        s = ((NumberFormat)fmt).format(123);
752        logln("Pattern \"" + pat + "\"");
753        logln(" Format 123 . " + s);
754        if (!s.equals("a'b123"))
755            errln("FAIL: Expected a'b123");
756    }
757
758    @Test
759    public void TestParseCurrencyTrailingSymbol() {
760        // see sun bug 4709840
761        NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.GERMANY);
762        float val = 12345.67f;
763        String str = fmt.format(val);
764        logln("val: " + val + " str: " + str);
765        try {
766            Number num = fmt.parse(str);
767            logln("num: " + num);
768        } catch (ParseException e) {
769            errln("parse of '" + str + "' threw exception: " + e);
770        }
771    }
772
773    /**
774     * Test the handling of the currency symbol in patterns.
775     **/
776    @Test
777    public void TestCurrencySign() {
778        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
779        StringBuffer pat = new StringBuffer("");
780        char currency = 0x00A4;
781        // "\xA4#,##0.00;-\xA4#,##0.00"
782        pat.append(currency).append("#,##0.00;-").append(currency).append("#,##0.00");
783        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
784        String s = ((NumberFormat) fmt).format(1234.56);
785        pat = new StringBuffer();
786        logln("Pattern \"" + fmt.toPattern() + "\"");
787        logln(" Format " + 1234.56 + " . " + s);
788        assertEquals("symbol, pos", "$1,234.56", s);
789
790        s = ((NumberFormat) fmt).format(-1234.56);
791        logln(" Format " + Double.toString(-1234.56) + " . " + s);
792        assertEquals("symbol, neg", "-$1,234.56", s);
793
794        pat.setLength(0);
795        // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
796        pat.append(currency).append(currency).append(" #,##0.00;").append(currency).append(currency).append(" -#,##0.00");
797        fmt = new DecimalFormat(pat.toString(), sym);
798        s = ((NumberFormat) fmt).format(1234.56);
799        logln("Pattern \"" + fmt.toPattern() + "\"");
800        logln(" Format " + Double.toString(1234.56) + " . " + s);
801        assertEquals("name, pos", "USD 1,234.56", s);
802
803        s = ((NumberFormat) fmt).format(-1234.56);
804        logln(" Format " + Double.toString(-1234.56) + " . " + s);
805        assertEquals("name, neg", "USD -1,234.56", s);
806    }
807
808    @Test
809    public void TestSpaceParsing() {
810        // the data are:
811        // the string to be parsed, parsed position, parsed error index
812        String[][] DATA = {
813                {"$124", "4", "-1"},
814                {"$124 $124", "4", "-1"},
815                {"$124 ", "4", "-1"},
816                {"$ 124 ", "5", "-1"},
817                {"$\u00A0124 ", "5", "-1"},
818                {" $ 124 ", "0", "0"}, // TODO: need to handle space correctly
819                {"124$", "0", "3"}, // TODO: need to handle space correctly
820                // {"124 $", "5", "-1"}, TODO: OK or NOT?
821                {"124 $", "0", "3"},
822        };
823        NumberFormat foo = NumberFormat.getCurrencyInstance();
824        for (int i = 0; i < DATA.length; ++i) {
825            ParsePosition parsePosition = new ParsePosition(0);
826            String stringToBeParsed = DATA[i][0];
827            int parsedPosition = Integer.parseInt(DATA[i][1]);
828            int errorIndex = Integer.parseInt(DATA[i][2]);
829            try {
830                Number result = foo.parse(stringToBeParsed, parsePosition);
831                if (parsePosition.getIndex() != parsedPosition ||
832                        parsePosition.getErrorIndex() != errorIndex) {
833                    errln("FAILED parse " + stringToBeParsed + "; parse position: " + parsePosition.getIndex() + "; error position: " + parsePosition.getErrorIndex());
834                }
835                if (parsePosition.getErrorIndex() == -1 &&
836                        result.doubleValue() != 124) {
837                    errln("FAILED parse " + stringToBeParsed + "; value " + result.doubleValue());
838                }
839            } catch (Exception e) {
840                errln("FAILED " + e.toString());
841            }
842        }
843    }
844
845
846    @Test
847    public void TestMultiCurrencySign() {
848        String[][] DATA = {
849                // the fields in the following test are:
850                // locale,
851                // currency pattern (with negative pattern),
852                // currency number to be formatted,
853                // currency format using currency symbol name, such as "$" for USD,
854                // currency format using currency ISO name, such as "USD",
855                // currency format using plural name, such as "US dollars".
856                // for US locale
857                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1234.56", "$1,234.56", "USD1,234.56", "US dollars1,234.56"},
858                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD1,234.56", "-US dollars1,234.56"},
859                {"en_US", "\u00A4#,##0.00;-\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollars1.00"},
860                // for CHINA locale
861                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1234.56", "\uFFE51,234.56", "CNY1,234.56", "\u4EBA\u6C11\u5E011,234.56"},
862                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "-1234.56", "(\uFFE51,234.56)", "(CNY1,234.56)", "(\u4EBA\u6C11\u5E011,234.56)"},
863                {"zh_CN", "\u00A4#,##0.00;(\u00A4#,##0.00)", "1", "\uFFE51.00", "CNY1.00", "\u4EBA\u6C11\u5E011.00"}
864        };
865
866        String doubleCurrencyStr = "\u00A4\u00A4";
867        String tripleCurrencyStr = "\u00A4\u00A4\u00A4";
868
869        for (int i=0; i<DATA.length; ++i) {
870            String locale = DATA[i][0];
871            String pat = DATA[i][1];
872            Double numberToBeFormat = new Double(DATA[i][2]);
873            DecimalFormatSymbols sym = new DecimalFormatSymbols(new ULocale(locale));
874            for (int j=1; j<=3; ++j) {
875                // j represents the number of currency sign in the pattern.
876                if (j == 2) {
877                    pat = pat.replaceAll("\u00A4", doubleCurrencyStr);
878                } else if (j == 3) {
879                    pat = pat.replaceAll("\u00A4\u00A4", tripleCurrencyStr);
880                }
881                DecimalFormat fmt = new DecimalFormat(pat, sym);
882                String s = ((NumberFormat) fmt).format(numberToBeFormat);
883                // DATA[i][3] is the currency format result using a
884                // single currency sign.
885                // DATA[i][4] is the currency format result using
886                // double currency sign.
887                // DATA[i][5] is the currency format result using
888                // triple currency sign.
889                // DATA[i][j+2] is the currency format result using
890                // 'j' number of currency sign.
891                String currencyFormatResult = DATA[i][2+j];
892                if (!s.equals(currencyFormatResult)) {
893                    errln("FAIL format: Expected " + currencyFormatResult);
894                }
895                try {
896                    // mix style parsing
897                    for (int k=3; k<=5; ++k) {
898                        // DATA[i][3] is the currency format result using a
899                        // single currency sign.
900                        // DATA[i][4] is the currency format result using
901                        // double currency sign.
902                        // DATA[i][5] is the currency format result using
903                        // triple currency sign.
904                        String oneCurrencyFormat = DATA[i][k];
905                        if (fmt.parse(oneCurrencyFormat).doubleValue() !=
906                                numberToBeFormat.doubleValue()) {
907                            errln("FAILED parse " + oneCurrencyFormat);
908                        }
909                    }
910                } catch (ParseException e) {
911                    errln("FAILED, DecimalFormat parse currency: " + e.toString());
912                }
913            }
914        }
915    }
916
917    @Test
918    public void TestCurrencyFormatForMixParsing() {
919        MeasureFormat curFmt = MeasureFormat.getCurrencyFormat(new ULocale("en_US"));
920        String[] formats = {
921                "$1,234.56",  // string to be parsed
922                "USD1,234.56",
923                "US dollars1,234.56",
924                "1,234.56 US dollars"
925        };
926        try {
927            for (int i = 0; i < formats.length; ++i) {
928                String stringToBeParsed = formats[i];
929                CurrencyAmount parsedVal = (CurrencyAmount)curFmt.parseObject(stringToBeParsed);
930                Number val = parsedVal.getNumber();
931                if (!val.equals(new BigDecimal("1234.56"))) {
932                    errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number. val=" + val);
933                }
934                if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
935                    errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
936                }
937            }
938        } catch (ParseException e) {
939            errln("parse FAILED: " + e.toString());
940        }
941    }
942
943    @Test
944    public void TestDecimalFormatCurrencyParse() {
945        // Locale.US
946        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
947        StringBuffer pat = new StringBuffer("");
948        char currency = 0x00A4;
949        // "\xA4#,##0.00;-\xA4#,##0.00"
950        pat.append(currency).append(currency).append(currency).append("#,##0.00;-").append(currency).append(currency).append(currency).append("#,##0.00");
951        DecimalFormat fmt = new DecimalFormat(pat.toString(), sym);
952        String[][] DATA = {
953                // the data are:
954                // string to be parsed, the parsed result (number)
955                {"$1.00", "1"},
956                {"USD1.00", "1"},
957                {"1.00 US dollar", "1"},
958                {"$1,234.56", "1234.56"},
959                {"USD1,234.56", "1234.56"},
960                {"1,234.56 US dollar", "1234.56"},
961        };
962        try {
963            for (int i = 0; i < DATA.length; ++i) {
964                String stringToBeParsed = DATA[i][0];
965                double parsedResult = Double.parseDouble(DATA[i][1]);
966                Number num = fmt.parse(stringToBeParsed);
967                if (num.doubleValue() != parsedResult) {
968                    errln("FAIL parse: Expected " + parsedResult);
969                }
970            }
971        } catch (ParseException e) {
972            errln("FAILED, DecimalFormat parse currency: " + e.toString());
973        }
974    }
975
976    /**
977     * Test localized currency patterns.
978     */
979    @Test
980    public void TestCurrency() {
981        String[] DATA = {
982                "fr", "CA", "", "1,50\u00a0$",
983                "de", "DE", "", "1,50\u00a0\u20AC",
984                "de", "DE", "PREEURO", "1,50\u00a0DM",
985                "fr", "FR", "", "1,50\u00a0\u20AC",
986                "fr", "FR", "PREEURO", "1,50\u00a0F",
987        };
988
989        for (int i=0; i<DATA.length; i+=4) {
990            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
991            NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
992            String s = fmt.format(1.50);
993            if (s.equals(DATA[i+3])) {
994                logln("Ok: 1.50 x " + locale + " => " + s);
995            } else {
996                logln("FAIL: 1.50 x " + locale + " => " + s +
997                        ", expected " + DATA[i+3]);
998            }
999        }
1000
1001        // format currency with CurrencyAmount
1002        for (int i=0; i<DATA.length; i+=4) {
1003            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
1004
1005            Currency curr = Currency.getInstance(locale);
1006            logln("\nName of the currency is: " + curr.getName(locale, Currency.LONG_NAME, new boolean[] {false}));
1007            CurrencyAmount cAmt = new CurrencyAmount(1.5, curr);
1008            logln("CurrencyAmount object's hashCode is: " + cAmt.hashCode()); //cover hashCode
1009
1010            NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
1011            String sCurr = fmt.format(cAmt);
1012            if (sCurr.equals(DATA[i+3])) {
1013                logln("Ok: 1.50 x " + locale + " => " + sCurr);
1014            } else {
1015                errln("FAIL: 1.50 x " + locale + " => " + sCurr +
1016                        ", expected " + DATA[i+3]);
1017            }
1018        }
1019
1020        //Cover MeasureFormat.getCurrencyFormat()
1021        ULocale save = ULocale.getDefault();
1022        ULocale.setDefault(ULocale.US);
1023        MeasureFormat curFmt = MeasureFormat.getCurrencyFormat();
1024        String strBuf = curFmt.format(new CurrencyAmount(new Float(1234.56), Currency.getInstance("USD")));
1025
1026        try {
1027            CurrencyAmount parsedVal = (CurrencyAmount)curFmt.parseObject(strBuf);
1028            Number val = parsedVal.getNumber();
1029            if (!val.equals(new BigDecimal("1234.56"))) {
1030                errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number. val=" + val);
1031            }
1032            if (!parsedVal.getCurrency().equals(Currency.getInstance("USD"))) {
1033                errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the currency");
1034            }
1035        }
1036        catch (ParseException e) {
1037            errln("FAIL: " + e.getMessage());
1038        }
1039        ULocale.setDefault(save);
1040    }
1041
1042    @Test
1043    public void TestCurrencyIsoPluralFormat() {
1044        String[][] DATA = {
1045                // the data are:
1046                // locale,
1047                // currency amount to be formatted,
1048                // currency ISO code to be formatted,
1049                // format result using CURRENCYSTYLE,
1050                // format result using ISOCURRENCYSTYLE,
1051                // format result using PLURALCURRENCYSTYLE,
1052                {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollars"},
1053                {"en_US", "1234.56", "USD", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
1054                {"en_US", "-1234.56", "USD", "-$1,234.56", "-USD1,234.56", "-1,234.56 US dollars"},
1055                {"zh_CN", "1", "USD", "US$1.00", "USD1.00", "1.00美元"},
1056                {"zh_CN", "1234.56", "USD", "US$1,234.56", "USD1,234.56", "1,234.56美元"},
1057                {"zh_CN", "1", "CNY", "¥1.00", "CNY1.00", "1.00人民币"},
1058                {"zh_CN", "1234.56", "CNY", "¥1,234.56", "CNY1,234.56", "1,234.56人民币"},
1059                {"ru_RU", "1", "RUB", "1,00 \u20BD", "1,00 RUB", "1,00 российского рубля"},
1060                {"ru_RU", "2", "RUB", "2,00 \u20BD", "2,00 RUB", "2,00 российского рубля"},
1061                {"ru_RU", "5", "RUB", "5,00 \u20BD", "5,00 RUB", "5,00 российского рубля"},
1062                // test locale without currency information
1063                {"root", "-1.23", "USD", "-US$ 1.23", "-USD 1.23", "-1.23 USD"},
1064                {"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
1065                {"root@numbers=arab", "-1.23", "USD", "\u061C-\u0661\u066B\u0662\u0663\u00A0US$", "\u061C-\u0661\u066B\u0662\u0663\u00A0USD", "\u061C-\u0661\u066B\u0662\u0663 USD"}, // ensure that the root locale is still used with modifiers
1066                {"es_AR", "1", "INR", "INR\u00A01,00", "INR\u00A01,00", "1,00 rupia india"},
1067                {"ar_EG", "1", "USD", "١٫٠٠\u00A0US$", "١٫٠٠\u00A0USD", "١٫٠٠ دولار أمريكي"},
1068        };
1069
1070        for (int i=0; i<DATA.length; ++i) {
1071            for (int k = NumberFormat.CURRENCYSTYLE;
1072                    k <= NumberFormat.PLURALCURRENCYSTYLE;
1073                    ++k) {
1074                // k represents currency format style.
1075                if ( k != NumberFormat.CURRENCYSTYLE &&
1076                        k != NumberFormat.ISOCURRENCYSTYLE &&
1077                        k != NumberFormat.PLURALCURRENCYSTYLE ) {
1078                    continue;
1079                }
1080                String localeString = DATA[i][0];
1081                Double numberToBeFormat = new Double(DATA[i][1]);
1082                String currencyISOCode = DATA[i][2];
1083                ULocale locale = new ULocale(localeString);
1084                NumberFormat numFmt = NumberFormat.getInstance(locale, k);
1085                numFmt.setCurrency(Currency.getInstance(currencyISOCode));
1086                String strBuf = numFmt.format(numberToBeFormat);
1087                int resultDataIndex = k-1;
1088                if ( k == NumberFormat.CURRENCYSTYLE ) {
1089                    resultDataIndex = k+2;
1090                }
1091                // DATA[i][resultDataIndex] is the currency format result
1092                // using 'k' currency style.
1093                String formatResult = DATA[i][resultDataIndex];
1094                if (!strBuf.equals(formatResult)) {
1095                    errln("FAIL: localeID: " + localeString + ", expected(" + formatResult.length() + "): \"" + formatResult + "\", actual(" + strBuf.length() + "): \"" + strBuf + "\"");
1096                }
1097                try {
1098                    // test parsing, and test parsing for all currency formats.
1099                    for (int j = 3; j < 6; ++j) {
1100                        // DATA[i][3] is the currency format result using
1101                        // CURRENCYSTYLE formatter.
1102                        // DATA[i][4] is the currency format result using
1103                        // ISOCURRENCYSTYLE formatter.
1104                        // DATA[i][5] is the currency format result using
1105                        // PLURALCURRENCYSTYLE formatter.
1106                        String oneCurrencyFormatResult = DATA[i][j];
1107                        Number val = numFmt.parse(oneCurrencyFormatResult);
1108                        if (val.doubleValue() != numberToBeFormat.doubleValue()) {
1109                            errln("FAIL: getCurrencyFormat of locale " + localeString + " failed roundtripping the number. val=" + val + "; expected: " + numberToBeFormat);
1110                        }
1111                    }
1112                }
1113                catch (ParseException e) {
1114                    errln("FAIL: " + e.getMessage());
1115                }
1116            }
1117        }
1118    }
1119
1120
1121    @Test
1122    public void TestMiscCurrencyParsing() {
1123        String[][] DATA = {
1124                // each has: string to be parsed, parsed position, error position
1125                {"1.00 ", "0", "4"},
1126                {"1.00 UAE dirha", "0", "4"},
1127                {"1.00 us dollar", "14", "-1"},
1128                {"1.00 US DOLLAR", "14", "-1"},
1129                {"1.00 usd", "0", "4"},
1130        };
1131        ULocale locale = new ULocale("en_US");
1132        for (int i=0; i<DATA.length; ++i) {
1133            String stringToBeParsed = DATA[i][0];
1134            int parsedPosition = Integer.parseInt(DATA[i][1]);
1135            int errorIndex = Integer.parseInt(DATA[i][2]);
1136            NumberFormat numFmt = NumberFormat.getInstance(locale, NumberFormat.CURRENCYSTYLE);
1137            ParsePosition parsePosition = new ParsePosition(0);
1138            Number val = numFmt.parse(stringToBeParsed, parsePosition);
1139            if (parsePosition.getIndex() != parsedPosition ||
1140                    parsePosition.getErrorIndex() != errorIndex) {
1141                errln("FAIL: parse failed. expected error position: " + errorIndex + "; actual: " + parsePosition.getErrorIndex());
1142                errln("FAIL: parse failed. expected position: " + parsedPosition +"; actual: " + parsePosition.getIndex());
1143            }
1144            if (parsePosition.getErrorIndex() == -1 &&
1145                    val.doubleValue() != 1.00) {
1146                errln("FAIL: parse failed. expected 1.00, actual:" + val);
1147            }
1148        }
1149    }
1150
1151    @Test
1152    public void TestParseCurrency() {
1153        class ParseCurrencyItem {
1154            private final String localeString;
1155            private final String descrip;
1156            private final String currStr;
1157            private final int    numExpectPos;
1158            private final int    numExpectVal;
1159            private final int    curExpectPos;
1160            private final int    curExpectVal;
1161            private final String curExpectCurr;
1162
1163            ParseCurrencyItem(String locStr, String desc, String curr, int numExPos, int numExVal, int curExPos, int curExVal, String curExCurr) {
1164                localeString  = locStr;
1165                descrip       = desc;
1166                currStr       = curr;
1167                numExpectPos  = numExPos;
1168                numExpectVal  = numExVal;
1169                curExpectPos  = curExPos;
1170                curExpectVal  = curExVal;
1171                curExpectCurr = curExCurr;
1172            }
1173            public String getLocaleString()  { return localeString; }
1174            public String getDescrip()       { return descrip; }
1175            public String getCurrStr()       { return currStr; }
1176            public int    getNumExpectPos()  { return numExpectPos; }
1177            public int    getNumExpectVal()  { return numExpectVal; }
1178            public int    getCurExpectPos()  { return curExpectPos; }
1179            public int    getCurExpectVal()  { return curExpectVal; }
1180            public String getCurExpectCurr() { return curExpectCurr; }
1181        }
1182        final ParseCurrencyItem[] parseCurrencyItems = {
1183                new ParseCurrencyItem( "en_US", "dollars2", "$2.00",            5,  2,  5,  2,  "USD" ),
1184                new ParseCurrencyItem( "en_US", "dollars4", "$4",               2,  4,  2,  4,  "USD" ),
1185                new ParseCurrencyItem( "en_US", "dollars9", "9\u00A0$",         0,  0,  0,  0,  ""    ),
1186                new ParseCurrencyItem( "en_US", "pounds3",  "\u00A33.00",       0,  0,  5,  3,  "GBP" ),
1187                new ParseCurrencyItem( "en_US", "pounds5",  "\u00A35",          0,  0,  2,  5,  "GBP" ),
1188                new ParseCurrencyItem( "en_US", "pounds7",  "7\u00A0\u00A3",    0,  0,  0,  0,  ""    ),
1189                new ParseCurrencyItem( "en_US", "euros8",   "\u20AC8",          0,  0,  2,  8,  "EUR" ),
1190
1191                new ParseCurrencyItem( "en_GB", "pounds3",  "\u00A33.00",       5,  3,  5,  3,  "GBP" ),
1192                new ParseCurrencyItem( "en_GB", "pounds5",  "\u00A35",          2,  5,  2,  5,  "GBP" ),
1193                new ParseCurrencyItem( "en_GB", "pounds7",  "7\u00A0\u00A3",    0,  0,  0,  0,  ""    ),
1194                new ParseCurrencyItem( "en_GB", "euros4",   "4,00\u00A0\u20AC", 0,  0,  0,  0,  ""    ),
1195                new ParseCurrencyItem( "en_GB", "euros6",   "6\u00A0\u20AC",    0,  0,  0,  0,  ""    ),
1196                new ParseCurrencyItem( "en_GB", "euros8",   "\u20AC8",          0,  0,  2,  8,  "EUR" ),
1197                new ParseCurrencyItem( "en_GB", "dollars4", "US$4",             0,  0,  4,  4,  "USD" ),
1198
1199                new ParseCurrencyItem( "fr_FR", "euros4",   "4,00\u00A0\u20AC", 6,  4,  6,  4,  "EUR" ),
1200                new ParseCurrencyItem( "fr_FR", "euros6",   "6\u00A0\u20AC",    3,  6,  3,  6,  "EUR" ),
1201                new ParseCurrencyItem( "fr_FR", "euros8",   "\u20AC8",          0,  0,  0,  0,  ""    ),
1202                new ParseCurrencyItem( "fr_FR", "dollars2", "$2.00",            0,  0,  0,  0,  ""    ),
1203                new ParseCurrencyItem( "fr_FR", "dollars4", "$4",               0,  0,  0,  0,  ""    ),
1204        };
1205        for (ParseCurrencyItem item: parseCurrencyItems) {
1206            String localeString = item.getLocaleString();
1207            ULocale uloc = new ULocale(localeString);
1208            NumberFormat fmt = null;
1209            try {
1210                fmt = NumberFormat.getCurrencyInstance(uloc);
1211            } catch (Exception e) {
1212                errln("NumberFormat.getCurrencyInstance fails for locale " + localeString);
1213                continue;
1214            }
1215            String currStr = item.getCurrStr();
1216            ParsePosition parsePos = new ParsePosition(0);
1217
1218            Number numVal = fmt.parse(currStr, parsePos);
1219            if ( parsePos.getIndex() != item.getNumExpectPos() || (numVal != null && numVal.intValue() != item.getNumExpectVal()) ) {
1220                if (numVal != null) {
1221                    errln("NumberFormat.getCurrencyInstance parse " + localeString + "/" + item.getDescrip() +
1222                            ", expect pos/val " + item.getNumExpectPos() + "/" + item.getNumExpectVal() +
1223                            ", get " + parsePos.getIndex() + "/" + numVal.intValue() );
1224                } else {
1225                    errln("NumberFormat.getCurrencyInstance parse " + localeString + "/" + item.getDescrip() +
1226                            ", expect pos/val " + item.getNumExpectPos() + "/" + item.getNumExpectVal() +
1227                            ", get " + parsePos.getIndex() + "/(NULL)" );
1228                }
1229            }
1230
1231            parsePos.setIndex(0);
1232            CurrencyAmount currAmt = fmt.parseCurrency(currStr, parsePos);
1233            if ( parsePos.getIndex() != item.getCurExpectPos() || (currAmt != null && (currAmt.getNumber().intValue() != item.getCurExpectVal() ||
1234                    currAmt.getCurrency().getCurrencyCode().compareTo(item.getCurExpectCurr()) != 0)) ) {
1235                if (currAmt != null) {
1236                    errln("NumberFormat.getCurrencyInstance parseCurrency " + localeString + "/" + item.getDescrip() +
1237                            ", expect pos/val/curr " + item.getCurExpectPos() + "/" + item.getCurExpectVal() + "/" + item.getCurExpectCurr() +
1238                            ", get " + parsePos.getIndex() + "/" + currAmt.getNumber().intValue() + "/" + currAmt.getCurrency().getCurrencyCode() );
1239                } else {
1240                    errln("NumberFormat.getCurrencyInstance parseCurrency " + localeString + "/" + item.getDescrip() +
1241                            ", expect pos/val/curr " + item.getCurExpectPos() + "/" + item.getCurExpectVal() + "/" + item.getCurExpectCurr() +
1242                            ", get " + parsePos.getIndex() + "/(NULL)" );
1243                }
1244            }
1245        }
1246    }
1247
1248    @Test
1249    public void TestParseCurrPatternWithDecStyle() {
1250        String currpat = "¤#,##0.00";
1251        String parsetxt = "x0y$";
1252        DecimalFormat decfmt = (DecimalFormat)NumberFormat.getInstance(new ULocale("en_US"), NumberFormat.NUMBERSTYLE);
1253        decfmt.applyPattern(currpat);
1254        ParsePosition ppos = new ParsePosition(0);
1255        Number value = decfmt.parse(parsetxt, ppos);
1256        if (ppos.getIndex() != 0) {
1257            errln("DecimalFormat.parse expected to fail but got ppos " + ppos.getIndex() + ", value " + value);
1258        }
1259    }
1260
1261    /**
1262     * Test the Currency object handling, new as of ICU 2.2.
1263     */
1264    @Test
1265    public void TestCurrencyObject() {
1266        NumberFormat fmt =
1267                NumberFormat.getCurrencyInstance(Locale.US);
1268
1269        expectCurrency(fmt, null, 1234.56, "$1,234.56");
1270
1271        expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
1272                1234.56, "\u20AC1,234.56"); // Euro
1273
1274        expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
1275                1234.56, "\u00A51,235"); // Yen
1276
1277        expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
1278                1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
1279
1280        expectCurrency(fmt, Currency.getInstance(Locale.US),
1281                1234.56, "$1,234.56");
1282
1283        fmt = NumberFormat.getCurrencyInstance(Locale.FRANCE);
1284
1285        expectCurrency(fmt, null, 1234.56, "1 234,56 \u20AC");
1286
1287        expectCurrency(fmt, Currency.getInstance(Locale.JAPAN),
1288                1234.56, "1 235 JPY"); // Yen
1289
1290        expectCurrency(fmt, Currency.getInstance(new Locale("fr", "CH", "")),
1291                1234.56, "1 234,56 CHF"); // no more rounding here, see cldrbug 5548
1292
1293        expectCurrency(fmt, Currency.getInstance(Locale.US),
1294                1234.56, "1 234,56 $US");
1295
1296        expectCurrency(fmt, Currency.getInstance(Locale.FRANCE),
1297                1234.56, "1 234,56 \u20AC"); // Euro
1298    }
1299
1300    @Test
1301    public void TestCompatibleCurrencies() {
1302        NumberFormat fmt =
1303                NumberFormat.getCurrencyInstance(Locale.US);
1304        expectParseCurrency(fmt, Currency.getInstance(Locale.JAPAN), "\u00A51,235"); // Yen half-width
1305        expectParseCurrency(fmt, Currency.getInstance(Locale.JAPAN), "\uFFE51,235"); // Yen full-wdith
1306    }
1307
1308    @Test
1309    public void TestCurrencyPatterns() {
1310        int i;
1311        Locale[] locs = NumberFormat.getAvailableLocales();
1312        for (i=0; i<locs.length; ++i) {
1313            NumberFormat nf = NumberFormat.getCurrencyInstance(locs[i]);
1314            // Make sure currency formats do not have a variable number
1315            // of fraction digits
1316            int min = nf.getMinimumFractionDigits();
1317            int max = nf.getMaximumFractionDigits();
1318            if (min != max) {
1319                String a = nf.format(1.0);
1320                String b = nf.format(1.125);
1321                errln("FAIL: " + locs[i] +
1322                        " min fraction digits != max fraction digits; "+
1323                        "x 1.0 => " + a +
1324                        "; x 1.125 => " + b);
1325            }
1326
1327            // Make sure EURO currency formats have exactly 2 fraction digits
1328            if (nf instanceof DecimalFormat) {
1329                Currency curr = ((DecimalFormat) nf).getCurrency();
1330                if (curr != null && "EUR".equals(curr.getCurrencyCode())) {
1331                    if (min != 2 || max != 2) {
1332                        String a = nf.format(1.0);
1333                        errln("FAIL: " + locs[i] +
1334                                " is a EURO format but it does not have 2 fraction digits; "+
1335                                "x 1.0 => " +
1336                                a);
1337                    }
1338                }
1339            }
1340        }
1341    }
1342
1343    /**
1344     * Do rudimentary testing of parsing.
1345     */
1346    @Test
1347    public void TestParse() {
1348        String arg = "0.0";
1349        DecimalFormat format = new DecimalFormat("00");
1350        double aNumber = 0l;
1351        try {
1352            aNumber = format.parse(arg).doubleValue();
1353        } catch (ParseException e) {
1354            System.out.println(e);
1355        }
1356        logln("parse(" + arg + ") = " + aNumber);
1357    }
1358
1359    /**
1360     * Test proper rounding by the format method.
1361     */
1362    @Test
1363    public void TestRounding487() {
1364
1365        NumberFormat nf = NumberFormat.getInstance();
1366        roundingTest(nf, 0.00159999, 4, "0.0016");
1367        roundingTest(nf, 0.00995, 4, "0.01");
1368
1369        roundingTest(nf, 12.3995, 3, "12.4");
1370
1371        roundingTest(nf, 12.4999, 0, "12");
1372        roundingTest(nf, - 19.5, 0, "-20");
1373
1374    }
1375
1376    /**
1377     * Test the functioning of the secondary grouping value.
1378     */
1379    @Test
1380    public void TestSecondaryGrouping() {
1381
1382        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1383        DecimalFormat f = new DecimalFormat("#,##,###", US);
1384
1385        expect(f, 123456789L, "12,34,56,789");
1386        expectPat(f, "#,##,###");
1387        f.applyPattern("#,###");
1388
1389        f.setSecondaryGroupingSize(4);
1390        expect(f, 123456789L, "12,3456,789");
1391        expectPat(f, "#,####,###");
1392        NumberFormat g = NumberFormat.getInstance(new Locale("hi", "IN"));
1393
1394        String out = "";
1395        long l = 1876543210L;
1396        out = g.format(l);
1397
1398        // expect "1,87,65,43,210", but with Hindi digits
1399        //         01234567890123
1400        boolean ok = true;
1401        if (out.length() != 14) {
1402            ok = false;
1403        } else {
1404            for (int i = 0; i < out.length(); ++i) {
1405                boolean expectGroup = false;
1406                switch (i) {
1407                case 1 :
1408                case 4 :
1409                case 7 :
1410                case 10 :
1411                    expectGroup = true;
1412                    break;
1413                }
1414                // Later -- fix this to get the actual grouping
1415                // character from the resource bundle.
1416                boolean isGroup = (out.charAt(i) == 0x002C);
1417                if (isGroup != expectGroup) {
1418                    ok = false;
1419                    break;
1420                }
1421            }
1422        }
1423        if (!ok) {
1424            errln("FAIL  Expected "+ l + " x hi_IN . \"1,87,65,43,210\" (with Hindi digits), got \""
1425                    + out + "\"");
1426        } else {
1427            logln("Ok    " + l + " x hi_IN . \"" + out + "\"");
1428        }
1429    }
1430
1431    /*
1432     * Internal test utility.
1433     */
1434    private void roundingTest(NumberFormat nf, double x, int maxFractionDigits, final String expected) {
1435        nf.setMaximumFractionDigits(maxFractionDigits);
1436        String out = nf.format(x);
1437        logln(x + " formats with " + maxFractionDigits + " fractional digits to " + out);
1438        if (!out.equals(expected))
1439            errln("FAIL: Expected " + expected);
1440    }
1441
1442    /**
1443     * Upgrade to alphaWorks
1444     */
1445    @Test
1446    public void TestExponent() {
1447        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1448        DecimalFormat fmt1 = new DecimalFormat("0.###E0", US);
1449        DecimalFormat fmt2 = new DecimalFormat("0.###E+0", US);
1450        int n = 1234;
1451        expect2(fmt1, n, "1.234E3");
1452        expect2(fmt2, n, "1.234E+3");
1453        expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
1454
1455    }
1456
1457    /**
1458     * Upgrade to alphaWorks
1459     */
1460    @Test
1461    public void TestScientific() {
1462
1463        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1464
1465        // Test pattern round-trip
1466        final String PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000", "0.###E0;[0.###E0]" };
1467        int PAT_length = PAT.length;
1468        int DIGITS[] = {
1469                // min int, max int, min frac, max frac
1470                0, 1, 0, 0, // "#E0"
1471                1, 1, 0, 4, // "0.####E0"
1472                2, 2, 3, 3, // "00.000E00"
1473                1, 3, 0, 4, // "##0.####E000"
1474                1, 1, 0, 3, // "0.###E0;[0.###E0]"
1475        };
1476        for (int i = 0; i < PAT_length; ++i) {
1477            String pat = PAT[i];
1478            DecimalFormat df = new DecimalFormat(pat, US);
1479            String pat2 = df.toPattern();
1480            if (pat.equals(pat2)) {
1481                logln("Ok   Pattern rt \"" + pat + "\" . \"" + pat2 + "\"");
1482            } else {
1483                errln("FAIL Pattern rt \"" + pat + "\" . \"" + pat2 + "\"");
1484            }
1485            // Make sure digit counts match what we expect
1486            if (df.getMinimumIntegerDigits() != DIGITS[4 * i]
1487                    || df.getMaximumIntegerDigits() != DIGITS[4 * i + 1]
1488                            || df.getMinimumFractionDigits() != DIGITS[4 * i + 2]
1489                                    || df.getMaximumFractionDigits() != DIGITS[4 * i + 3]) {
1490                errln("FAIL \""+ pat+ "\" min/max int; min/max frac = "
1491                        + df.getMinimumIntegerDigits() + "/"
1492                        + df.getMaximumIntegerDigits() + ";"
1493                        + df.getMinimumFractionDigits() + "/"
1494                        + df.getMaximumFractionDigits() + ", expect "
1495                        + DIGITS[4 * i] + "/"
1496                        + DIGITS[4 * i + 1] + ";"
1497                        + DIGITS[4 * i + 2] + "/"
1498                        + DIGITS[4 * i + 3]);
1499            }
1500        }
1501
1502        expect2(new DecimalFormat("#E0", US), 12345.0, "1.2345E4");
1503        expect(new DecimalFormat("0E0", US), 12345.0, "1E4");
1504
1505        // pattern of NumberFormat.getScientificInstance(Locale.US) = "0.######E0" not "#E0"
1506        // so result = 1.234568E4 not 1.2345678901E4
1507        //when the pattern problem is finalized, delete comment mark'//'
1508        //of the following code
1509        expect2(NumberFormat.getScientificInstance(Locale.US), 12345.678901, "1.2345678901E4");
1510        logln("Testing NumberFormat.getScientificInstance(ULocale) ...");
1511        expect2(NumberFormat.getScientificInstance(ULocale.US), 12345.678901, "1.2345678901E4");
1512
1513        expect(new DecimalFormat("##0.###E0", US), 12345.0, "12.34E3");
1514        expect(new DecimalFormat("##0.###E0", US), 12345.00001, "12.35E3");
1515        expect2(new DecimalFormat("##0.####E0", US), 12345, "12.345E3");
1516
1517        // pattern of NumberFormat.getScientificInstance(Locale.US) = "0.######E0" not "#E0"
1518        // so result = 1.234568E4 not 1.2345678901E4
1519        expect2(NumberFormat.getScientificInstance(Locale.FRANCE), 12345.678901, "1,2345678901E4");
1520        logln("Testing NumberFormat.getScientificInstance(ULocale) ...");
1521        expect2(NumberFormat.getScientificInstance(ULocale.FRANCE), 12345.678901, "1,2345678901E4");
1522
1523        expect(new DecimalFormat("##0.####E0", US), 789.12345e-9, "789.12E-9");
1524        expect2(new DecimalFormat("##0.####E0", US), 780.e-9, "780E-9");
1525        expect(new DecimalFormat(".###E0", US), 45678.0, ".457E5");
1526        expect2(new DecimalFormat(".###E0", US), 0, ".0E0");
1527        /*
1528        expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
1529                                     new DecimalFormat("##E0", US),
1530                                     new DecimalFormat("####E0", US),
1531                                     new DecimalFormat("0E0", US),
1532                                     new DecimalFormat("00E0", US),
1533                                     new DecimalFormat("000E0", US),
1534                                   },
1535               new Long(45678000),
1536               new String[] { "4.5678E7",
1537                              "45.678E6",
1538                              "4567.8E4",
1539                              "5E7",
1540                              "46E6",
1541                              "457E5",
1542                            }
1543               );
1544        !
1545        ! Unroll this test into individual tests below...
1546        !
1547         */
1548        expect2(new DecimalFormat("#E0", US), 45678000, "4.5678E7");
1549        expect2(new DecimalFormat("##E0", US), 45678000, "45.678E6");
1550        expect2(new DecimalFormat("####E0", US), 45678000, "4567.8E4");
1551        expect(new DecimalFormat("0E0", US), 45678000, "5E7");
1552        expect(new DecimalFormat("00E0", US), 45678000, "46E6");
1553        expect(new DecimalFormat("000E0", US), 45678000, "457E5");
1554        /*
1555        expect(new DecimalFormat("###E0", US, status),
1556               new Object[] { new Double(0.0000123), "12.3E-6",
1557                              new Double(0.000123), "123E-6",
1558                              new Double(0.00123), "1.23E-3",
1559                              new Double(0.0123), "12.3E-3",
1560                              new Double(0.123), "123E-3",
1561                              new Double(1.23), "1.23E0",
1562                              new Double(12.3), "12.3E0",
1563                              new Double(123), "123E0",
1564                              new Double(1230), "1.23E3",
1565                             });
1566        !
1567        ! Unroll this test into individual tests below...
1568        !
1569         */
1570        expect2(new DecimalFormat("###E0", US), 0.0000123, "12.3E-6");
1571        expect2(new DecimalFormat("###E0", US), 0.000123, "123E-6");
1572        expect2(new DecimalFormat("###E0", US), 0.00123, "1.23E-3");
1573        expect2(new DecimalFormat("###E0", US), 0.0123, "12.3E-3");
1574        expect2(new DecimalFormat("###E0", US), 0.123, "123E-3");
1575        expect2(new DecimalFormat("###E0", US), 1.23, "1.23E0");
1576        expect2(new DecimalFormat("###E0", US), 12.3, "12.3E0");
1577        expect2(new DecimalFormat("###E0", US), 123.0, "123E0");
1578        expect2(new DecimalFormat("###E0", US), 1230.0, "1.23E3");
1579        /*
1580        expect(new DecimalFormat("0.#E+00", US, status),
1581               new Object[] { new Double(0.00012), "1.2E-04",
1582                              new Long(12000),     "1.2E+04",
1583                             });
1584        !
1585        ! Unroll this test into individual tests below...
1586        !
1587         */
1588        expect2(new DecimalFormat("0.#E+00", US), 0.00012, "1.2E-04");
1589        expect2(new DecimalFormat("0.#E+00", US), 12000, "1.2E+04");
1590    }
1591
1592    /**
1593     * Upgrade to alphaWorks
1594     */
1595    @Test
1596    public void TestPad() {
1597
1598        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1599        expect2(new DecimalFormat("*^##.##", US), 0, "^^^^0");
1600        expect2(new DecimalFormat("*^##.##", US), -1.3, "^-1.3");
1601        expect2(
1602                new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
1603                0,
1604                "0.0E0______ g-m/s^2");
1605        expect(
1606                new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
1607                1.0 / 3,
1608                "333.333E-3_ g-m/s^2");
1609        expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US), 0, "0.0______ g-m/s^2");
1610        expect(
1611                new DecimalFormat("##0.0####*_ 'g-m/s^2'", US),
1612                1.0 / 3,
1613                "0.33333__ g-m/s^2");
1614
1615        // Test padding before a sign
1616        final String formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
1617        expect2(new DecimalFormat(formatStr, US), -10, "xxxxxxxxxx(10.0)");
1618        expect2(new DecimalFormat(formatStr, US), -1000, "xxxxxxx(1,000.0)");
1619        expect2(new DecimalFormat(formatStr, US), -1000000, "xxx(1,000,000.0)");
1620        expect2(new DecimalFormat(formatStr, US), -100.37, "xxxxxxxx(100.37)");
1621        expect2(new DecimalFormat(formatStr, US), -10456.37, "xxxxx(10,456.37)");
1622        expect2(new DecimalFormat(formatStr, US), -1120456.37, "xx(1,120,456.37)");
1623        expect2(new DecimalFormat(formatStr, US), -112045600.37, "(112,045,600.37)");
1624        expect2(new DecimalFormat(formatStr, US), -1252045600.37, "(1,252,045,600.37)");
1625
1626        expect2(new DecimalFormat(formatStr, US), 10, "xxxxxxxxxxxx10.0");
1627        expect2(new DecimalFormat(formatStr, US), 1000, "xxxxxxxxx1,000.0");
1628        expect2(new DecimalFormat(formatStr, US), 1000000, "xxxxx1,000,000.0");
1629        expect2(new DecimalFormat(formatStr, US), 100.37, "xxxxxxxxxx100.37");
1630        expect2(new DecimalFormat(formatStr, US), 10456.37, "xxxxxxx10,456.37");
1631        expect2(new DecimalFormat(formatStr, US), 1120456.37, "xxxx1,120,456.37");
1632        expect2(new DecimalFormat(formatStr, US), 112045600.37, "xx112,045,600.37");
1633        expect2(new DecimalFormat(formatStr, US), 10252045600.37, "10,252,045,600.37");
1634
1635        // Test padding between a sign and a number
1636        final String formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
1637        expect2(new DecimalFormat(formatStr2, US), -10, "(10.0xxxxxxxxxx)");
1638        expect2(new DecimalFormat(formatStr2, US), -1000, "(1,000.0xxxxxxx)");
1639        expect2(new DecimalFormat(formatStr2, US), -1000000, "(1,000,000.0xxx)");
1640        expect2(new DecimalFormat(formatStr2, US), -100.37, "(100.37xxxxxxxx)");
1641        expect2(new DecimalFormat(formatStr2, US), -10456.37, "(10,456.37xxxxx)");
1642        expect2(new DecimalFormat(formatStr2, US), -1120456.37, "(1,120,456.37xx)");
1643        expect2(new DecimalFormat(formatStr2, US), -112045600.37, "(112,045,600.37)");
1644        expect2(new DecimalFormat(formatStr2, US), -1252045600.37, "(1,252,045,600.37)");
1645
1646        expect2(new DecimalFormat(formatStr2, US), 10, "10.0xxxxxxxxxxxx");
1647        expect2(new DecimalFormat(formatStr2, US), 1000, "1,000.0xxxxxxxxx");
1648        expect2(new DecimalFormat(formatStr2, US), 1000000, "1,000,000.0xxxxx");
1649        expect2(new DecimalFormat(formatStr2, US), 100.37, "100.37xxxxxxxxxx");
1650        expect2(new DecimalFormat(formatStr2, US), 10456.37, "10,456.37xxxxxxx");
1651        expect2(new DecimalFormat(formatStr2, US), 1120456.37, "1,120,456.37xxxx");
1652        expect2(new DecimalFormat(formatStr2, US), 112045600.37, "112,045,600.37xx");
1653        expect2(new DecimalFormat(formatStr2, US), 10252045600.37, "10,252,045,600.37");
1654
1655        //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
1656        DecimalFormat fmt = new DecimalFormat("#", US);
1657        char padString = 'P';
1658        fmt.setPadCharacter(padString);
1659        expectPad(fmt, "*P##.##", DecimalFormat.PAD_BEFORE_PREFIX, 5, padString);
1660        fmt.setPadCharacter('^');
1661        expectPad(fmt, "*^#", DecimalFormat.PAD_BEFORE_PREFIX, 1, '^');
1662        //commented untill implementation is complete
1663        /*  fmt.setPadCharacter((UnicodeString)"^^^");
1664          expectPad(fmt, "*^^^#", DecimalFormat.kPadBeforePrefix, 3, (UnicodeString)"^^^");
1665          padString.remove();
1666          padString.append((UChar)0x0061);
1667          padString.append((UChar)0x0302);
1668          fmt.setPadCharacter(padString);
1669          UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
1670          UnicodeString pattern(patternChars);
1671          expectPad(fmt, pattern , DecimalFormat.kPadBeforePrefix, 4, padString);
1672         */
1673    }
1674
1675    /**
1676     * Upgrade to alphaWorks
1677     */
1678    @Test
1679    public void TestPatterns2() {
1680        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1681        DecimalFormat fmt = new DecimalFormat("#", US);
1682
1683        char hat = 0x005E; /*^*/
1684
1685        expectPad(fmt, "*^#", DecimalFormat.PAD_BEFORE_PREFIX, 1, hat);
1686        expectPad(fmt, "$*^#", DecimalFormat.PAD_AFTER_PREFIX, 2, hat);
1687        expectPad(fmt, "#*^", DecimalFormat.PAD_BEFORE_SUFFIX, 1, hat);
1688        expectPad(fmt, "#$*^", DecimalFormat.PAD_AFTER_SUFFIX, 2, hat);
1689        expectPad(fmt, "$*^$#", -1);
1690        expectPad(fmt, "#$*^$", -1);
1691        expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat.PAD_BEFORE_SUFFIX, 12, (char) 0x0078 /*x*/);
1692        expectPad(fmt, "''#0*x", DecimalFormat.PAD_BEFORE_SUFFIX, 3, (char) 0x0078 /*x*/);
1693        expectPad(fmt, "'I''ll'*a###.##", DecimalFormat.PAD_AFTER_PREFIX, 10, (char) 0x0061 /*a*/);
1694
1695        fmt.applyPattern("AA#,##0.00ZZ");
1696        fmt.setPadCharacter(hat);
1697
1698        fmt.setFormatWidth(10);
1699
1700        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_PREFIX);
1701        expectPat(fmt, "*^AA#,##0.00ZZ");
1702
1703        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_SUFFIX);
1704        expectPat(fmt, "AA#,##0.00*^ZZ");
1705
1706        fmt.setPadPosition(DecimalFormat.PAD_AFTER_SUFFIX);
1707        expectPat(fmt, "AA#,##0.00ZZ*^");
1708
1709        //            12  3456789012
1710        String exp = "AA*^#,##0.00ZZ";
1711        fmt.setFormatWidth(12);
1712        fmt.setPadPosition(DecimalFormat.PAD_AFTER_PREFIX);
1713        expectPat(fmt, exp);
1714
1715        fmt.setFormatWidth(13);
1716        //              12  34567890123
1717        expectPat(fmt, "AA*^##,##0.00ZZ");
1718
1719        fmt.setFormatWidth(14);
1720        //              12  345678901234
1721        expectPat(fmt, "AA*^###,##0.00ZZ");
1722
1723        fmt.setFormatWidth(15);
1724        //              12  3456789012345
1725        expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
1726
1727        fmt.setFormatWidth(16);
1728        //              12  34567890123456
1729        expectPat(fmt, "AA*^#,###,##0.00ZZ");
1730    }
1731
1732    @Test
1733    public void TestRegistration() {
1734        final ULocale SRC_LOC = ULocale.FRANCE;
1735        final ULocale SWAP_LOC = ULocale.US;
1736
1737        class TestFactory extends SimpleNumberFormatFactory {
1738            NumberFormat currencyStyle;
1739
1740            TestFactory() {
1741                super(SRC_LOC, true);
1742                currencyStyle = NumberFormat.getIntegerInstance(SWAP_LOC);
1743            }
1744
1745            @Override
1746            public NumberFormat createFormat(ULocale loc, int formatType) {
1747                if (formatType == FORMAT_CURRENCY) {
1748                    return currencyStyle;
1749                }
1750                return null;
1751            }
1752        }
1753
1754        NumberFormat f0 = NumberFormat.getIntegerInstance(SWAP_LOC);
1755        NumberFormat f1 = NumberFormat.getIntegerInstance(SRC_LOC);
1756        NumberFormat f2 = NumberFormat.getCurrencyInstance(SRC_LOC);
1757        Object key = NumberFormat.registerFactory(new TestFactory());
1758        NumberFormat f3 = NumberFormat.getCurrencyInstance(SRC_LOC);
1759        NumberFormat f4 = NumberFormat.getIntegerInstance(SRC_LOC);
1760        NumberFormat.unregister(key); // restore for other tests
1761        NumberFormat f5 = NumberFormat.getCurrencyInstance(SRC_LOC);
1762
1763        float n = 1234.567f;
1764        logln("f0 swap int: " + f0.format(n));
1765        logln("f1 src int: " + f1.format(n));
1766        logln("f2 src cur: " + f2.format(n));
1767        logln("f3 reg cur: " + f3.format(n));
1768        logln("f4 reg int: " + f4.format(n));
1769        logln("f5 unreg cur: " + f5.format(n));
1770
1771        if (!f3.format(n).equals(f0.format(n))) {
1772            errln("registered service did not match");
1773        }
1774        if (!f4.format(n).equals(f1.format(n))) {
1775            errln("registered service did not inherit");
1776        }
1777        if (!f5.format(n).equals(f2.format(n))) {
1778            errln("unregistered service did not match original");
1779        }
1780    }
1781
1782    @Test
1783    public void TestScientific2() {
1784        // jb 2552
1785        DecimalFormat fmt = (DecimalFormat)NumberFormat.getCurrencyInstance();
1786        Number num = new Double(12.34);
1787        expect(fmt, num, "$12.34");
1788        fmt.setScientificNotation(true);
1789        expect(fmt, num, "$1.23E1");
1790        fmt.setScientificNotation(false);
1791        expect(fmt, num, "$12.34");
1792    }
1793
1794    @Test
1795    public void TestScientificGrouping() {
1796        // jb 2552
1797        DecimalFormat fmt = new DecimalFormat("###.##E0");
1798        expect(fmt, .01234, "12.3E-3");
1799        expect(fmt, .1234, "123E-3");
1800        expect(fmt, 1.234, "1.23E0");
1801        expect(fmt, 12.34, "12.3E0");
1802        expect(fmt, 123.4, "123E0");
1803        expect(fmt, 1234, "1.23E3");
1804    }
1805
1806    // additional coverage tests
1807
1808    // sigh, can't have static inner classes, why not?
1809
1810    static final class PI extends Number {
1811        /**
1812         * For serialization
1813         */
1814        private static final long serialVersionUID = -305601227915602172L;
1815
1816        private PI() {}
1817        @Override
1818        public int intValue() { return (int)Math.PI; }
1819        @Override
1820        public long longValue() { return (long)Math.PI; }
1821        @Override
1822        public float  floatValue() { return (float)Math.PI; }
1823        @Override
1824        public double doubleValue() { return Math.PI; }
1825        @Override
1826        public byte byteValue() { return (byte)Math.PI; }
1827        @Override
1828        public short shortValue() { return (short)Math.PI; }
1829
1830        public static final Number INSTANCE = new PI();
1831    }
1832
1833    @Test
1834    public void TestCoverage() {
1835        NumberFormat fmt = NumberFormat.getNumberInstance(); // default locale
1836        logln(fmt.format(new BigInteger("1234567890987654321234567890987654321", 10)));
1837
1838        fmt = NumberFormat.getScientificInstance(); // default locale
1839
1840        logln(fmt.format(PI.INSTANCE));
1841
1842        try {
1843            logln(fmt.format("12345"));
1844            errln("numberformat of string did not throw exception");
1845        }
1846        catch (Exception e) {
1847            logln("PASS: numberformat of string failed as expected");
1848        }
1849
1850        int hash = fmt.hashCode();
1851        logln("hash code " + hash);
1852
1853        logln("compare to string returns: " + fmt.equals(""));
1854
1855        // For ICU 2.6 - alan
1856        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1857        DecimalFormat df = new DecimalFormat("'*&'' '\u00A4' ''&*' #,##0.00", US);
1858        df.setCurrency(Currency.getInstance("INR"));
1859        expect2(df, 1.0, "*&' \u20B9 '&* 1.00");
1860        expect2(df, -2.0, "-*&' \u20B9 '&* 2.00");
1861        df.applyPattern("#,##0.00 '*&'' '\u00A4' ''&*'");
1862        expect2(df, 2.0, "2.00 *&' \u20B9 '&*");
1863        expect2(df, -1.0, "-1.00 *&' \u20B9 '&*");
1864
1865        java.math.BigDecimal r;
1866
1867        r = df.getRoundingIncrement();
1868        if (r != null) {
1869            errln("FAIL: rounding = " + r + ", expect null");
1870        }
1871
1872        if (df.isScientificNotation()) {
1873            errln("FAIL: isScientificNotation = true, expect false");
1874        }
1875
1876        df.applyPattern("0.00000");
1877        df.setScientificNotation(true);
1878        if (!df.isScientificNotation()) {
1879            errln("FAIL: isScientificNotation = false, expect true");
1880        }
1881        df.setMinimumExponentDigits((byte)2);
1882        if (df.getMinimumExponentDigits() != 2) {
1883            errln("FAIL: getMinimumExponentDigits = " +
1884                    df.getMinimumExponentDigits() + ", expect 2");
1885        }
1886        df.setExponentSignAlwaysShown(true);
1887        if (!df.isExponentSignAlwaysShown()) {
1888            errln("FAIL: isExponentSignAlwaysShown = false, expect true");
1889        }
1890        df.setSecondaryGroupingSize(0);
1891        if (df.getSecondaryGroupingSize() != 0) {
1892            errln("FAIL: getSecondaryGroupingSize = " +
1893                    df.getSecondaryGroupingSize() + ", expect 0");
1894        }
1895        expect2(df, 3.14159, "3.14159E+00");
1896
1897        // DecimalFormatSymbols#getInstance
1898        DecimalFormatSymbols decsym1 = DecimalFormatSymbols.getInstance();
1899        DecimalFormatSymbols decsym2 = new DecimalFormatSymbols();
1900        if (!decsym1.equals(decsym2)) {
1901            errln("FAIL: DecimalFormatSymbols returned by getInstance()" +
1902                    "does not match new DecimalFormatSymbols().");
1903        }
1904        decsym1 = DecimalFormatSymbols.getInstance(Locale.JAPAN);
1905        decsym2 = DecimalFormatSymbols.getInstance(ULocale.JAPAN);
1906        if (!decsym1.equals(decsym2)) {
1907            errln("FAIL: DecimalFormatSymbols returned by getInstance(Locale.JAPAN)" +
1908                    "does not match the one returned by getInstance(ULocale.JAPAN).");
1909        }
1910
1911        // DecimalFormatSymbols#getAvailableLocales/#getAvailableULocales
1912        Locale[] allLocales = DecimalFormatSymbols.getAvailableLocales();
1913        if (allLocales.length == 0) {
1914            errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1915        } else {
1916            logln("PASS: " + allLocales.length +
1917                    " available locales returned by DecimalFormatSymbols.getAvailableLocales");
1918        }
1919        ULocale[] allULocales = DecimalFormatSymbols.getAvailableULocales();
1920        if (allULocales.length == 0) {
1921            errln("FAIL: Got a empty list for DecimalFormatSymbols.getAvailableLocales");
1922        } else {
1923            logln("PASS: " + allULocales.length +
1924                    " available locales returned by DecimalFormatSymbols.getAvailableULocales");
1925        }
1926    }
1927
1928    @Test
1929    public void TestWhiteSpaceParsing() {
1930        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
1931        DecimalFormat fmt = new DecimalFormat("a  b#0c  ", US);
1932        int n = 1234;
1933        expect(fmt, "a b1234c ", n);
1934        expect(fmt, "a   b1234c   ", n);
1935    }
1936
1937    /**
1938     * Test currencies whose display name is a ChoiceFormat.
1939     */
1940    @Test
1941    public void TestComplexCurrency() {
1942        //  CLDR No Longer uses complex currency symbols.
1943        //  Skipping this test.
1944        //        Locale loc = new Locale("kn", "IN", "");
1945        //        NumberFormat fmt = NumberFormat.getCurrencyInstance(loc);
1946
1947        //        expect2(fmt, 1.0, "Re.\u00a01.00");
1948        //        expect(fmt, 1.001, "Re.\u00a01.00"); // tricky
1949        //        expect2(fmt, 12345678.0, "Rs.\u00a01,23,45,678.00");
1950        //        expect2(fmt, 0.5, "Rs.\u00a00.50");
1951        //        expect2(fmt, -1.0, "-Re.\u00a01.00");
1952        //        expect2(fmt, -10.0, "-Rs.\u00a010.00");
1953    }
1954
1955    @Test
1956    public void TestCurrencyKeyword() {
1957        ULocale locale = new ULocale("th_TH@currency=QQQ");
1958        NumberFormat format = NumberFormat.getCurrencyInstance(locale);
1959        String result = format.format(12.34f);
1960        if (!"QQQ12.34".equals(result)) {
1961            errln("got unexpected currency: " + result);
1962        }
1963    }
1964
1965    /**
1966     * Test alternate numbering systems
1967     */
1968    @Test
1969    public void TestNumberingSystems() {
1970        class TestNumberingSystemItem {
1971            private final String localeName;
1972            private final double value;
1973            private final boolean isRBNF;
1974            private final String expectedResult;
1975
1976            TestNumberingSystemItem(String loc, double val, boolean rbnf, String exp) {
1977                localeName  = loc;
1978                value = val;
1979                isRBNF = rbnf;
1980                expectedResult = exp;
1981            }
1982        }
1983
1984        final TestNumberingSystemItem[] DATA = {
1985                new TestNumberingSystemItem( "en_US@numbers=thai",        1234.567, false, "\u0e51,\u0e52\u0e53\u0e54.\u0e55\u0e56\u0e57" ),
1986                new TestNumberingSystemItem( "en_US@numbers=thai",        1234.567, false, "\u0E51,\u0E52\u0E53\u0E54.\u0E55\u0E56\u0E57" ),
1987                new TestNumberingSystemItem( "en_US@numbers=hebr",        5678.0,   true,  "\u05D4\u05F3\u05EA\u05E8\u05E2\u05F4\u05D7" ),
1988                new TestNumberingSystemItem( "en_US@numbers=arabext",     1234.567, false, "\u06F1\u066c\u06F2\u06F3\u06F4\u066b\u06F5\u06F6\u06F7" ),
1989                new TestNumberingSystemItem( "de_DE@numbers=foobar",      1234.567, false, "1.234,567" ),
1990                new TestNumberingSystemItem( "ar_EG",                     1234.567, false, "\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666\u0667" ),
1991                new TestNumberingSystemItem( "th_TH@numbers=traditional", 1234.567, false, "\u0E51,\u0E52\u0E53\u0E54.\u0E55\u0E56\u0E57" ), // fall back to native per TR35
1992                new TestNumberingSystemItem( "ar_MA",                     1234.567, false, "1.234,567" ),
1993                new TestNumberingSystemItem( "en_US@numbers=hanidec",     1234.567, false, "\u4e00,\u4e8c\u4e09\u56db.\u4e94\u516d\u4e03" ),
1994                new TestNumberingSystemItem( "ta_IN@numbers=native",      1234.567, false, "\u0BE7,\u0BE8\u0BE9\u0BEA.\u0BEB\u0BEC\u0BED" ),
1995                new TestNumberingSystemItem( "ta_IN@numbers=traditional", 1235.0,   true,  "\u0BF2\u0BE8\u0BF1\u0BE9\u0BF0\u0BEB" ),
1996                new TestNumberingSystemItem( "ta_IN@numbers=finance",     1234.567, false, "1,234.567" ), // fall back to default per TR35
1997                new TestNumberingSystemItem( "zh_TW@numbers=native",      1234.567, false, "\u4e00,\u4e8c\u4e09\u56db.\u4e94\u516d\u4e03" ),
1998                new TestNumberingSystemItem( "zh_TW@numbers=traditional", 1234.567, true,  "\u4E00\u5343\u4E8C\u767E\u4E09\u5341\u56DB\u9EDE\u4E94\u516D\u4E03" ),
1999                new TestNumberingSystemItem( "zh_TW@numbers=finance",     1234.567, true,  "\u58F9\u4EDF\u8CB3\u4F70\u53C3\u62FE\u8086\u9EDE\u4F0D\u9678\u67D2" )
2000        };
2001
2002
2003        for (TestNumberingSystemItem item : DATA) {
2004            ULocale loc = new ULocale(item.localeName);
2005            NumberFormat fmt = NumberFormat.getInstance(loc);
2006            if (item.isRBNF) {
2007                expect3(fmt,item.value,item.expectedResult);
2008            } else {
2009                expect2(fmt,item.value,item.expectedResult);
2010            }
2011        }
2012    }
2013
2014    // Coverage tests for methods not being called otherwise.
2015    @Test
2016    public void TestNumberingSystemCoverage() {
2017        // Test getAvaliableNames
2018        String[] availableNames = NumberingSystem.getAvailableNames();
2019        if (availableNames == null || availableNames.length <= 0) {
2020            errln("ERROR: NumberingSystem.getAvailableNames() returned a null or empty array.");
2021        } else {
2022            boolean latnFound = false;
2023            for (String name : availableNames){
2024                if ("latn".equals(name)) {
2025                    latnFound = true;
2026                    break;
2027                }
2028            }
2029
2030            if (!latnFound) {
2031                errln("ERROR: 'latn' numbering system not found on NumberingSystem.getAvailableNames().");
2032            }
2033        }
2034
2035        // Test NumberingSystem.getInstance()
2036        NumberingSystem ns1 = NumberingSystem.getInstance();
2037        if (ns1 == null || ns1.isAlgorithmic()) {
2038            errln("ERROR: NumberingSystem.getInstance() returned a null or invalid NumberingSystem");
2039        }
2040
2041        // Test NumberingSystem.getInstance(int,boolean,String)
2042        /* Parameters used: the ones used in the default constructor
2043         * radix = 10;
2044         * algorithmic = false;
2045         * desc = "0123456789";
2046         */
2047        NumberingSystem ns2 = NumberingSystem.getInstance(10, false, "0123456789");
2048        if (ns2 == null || ns2.isAlgorithmic()) {
2049            errln("ERROR: NumberingSystem.getInstance(int,boolean,String) returned a null or invalid NumberingSystem");
2050        }
2051
2052        // Test NumberingSystem.getInstance(Locale)
2053        NumberingSystem ns3 = NumberingSystem.getInstance(Locale.ENGLISH);
2054        if (ns3 == null || ns3.isAlgorithmic()) {
2055            errln("ERROR: NumberingSystem.getInstance(Locale) returned a null or invalid NumberingSystem");
2056        }
2057    }
2058
2059    @Test
2060    public void Test6816() {
2061        Currency cur1 = Currency.getInstance(new Locale("und", "PH"));
2062
2063        NumberFormat nfmt = NumberFormat.getCurrencyInstance(new Locale("und", "PH"));
2064        DecimalFormatSymbols decsym = ((DecimalFormat)nfmt).getDecimalFormatSymbols();
2065        Currency cur2 = decsym.getCurrency();
2066
2067        if ( !cur1.getCurrencyCode().equals("PHP") || !cur2.getCurrencyCode().equals("PHP")) {
2068            errln("FAIL: Currencies should match PHP: cur1 = "+cur1.getCurrencyCode()+"; cur2 = "+cur2.getCurrencyCode());
2069        }
2070
2071    }
2072
2073    @Test
2074    public void TestThreadedFormat() {
2075
2076        class FormatTask implements Runnable {
2077            DecimalFormat fmt;
2078            StringBuffer buf;
2079            boolean inc;
2080            float num;
2081
2082            FormatTask(DecimalFormat fmt, int index) {
2083                this.fmt = fmt;
2084                this.buf = new StringBuffer();
2085                this.inc = (index & 0x1) == 0;
2086                this.num = inc ? 0 : 10000;
2087            }
2088
2089            @Override
2090            public void run() {
2091                if (inc) {
2092                    while (num < 10000) {
2093                        buf.append(fmt.format(num) + "\n");
2094                        num += 3.14159;
2095                    }
2096                } else {
2097                    while (num > 0) {
2098                        buf.append(fmt.format(num) + "\n");
2099                        num -= 3.14159;
2100                    }
2101                }
2102            }
2103
2104            String result() {
2105                return buf.toString();
2106            }
2107        }
2108
2109        DecimalFormat fmt = new DecimalFormat("0.####");
2110        FormatTask[] tasks = new FormatTask[8];
2111        for (int i = 0; i < tasks.length; ++i) {
2112            tasks[i] = new FormatTask(fmt, i);
2113        }
2114
2115        TestUtil.runUntilDone(tasks);
2116
2117        for (int i = 2; i < tasks.length; i++) {
2118            String str1 = tasks[i].result();
2119            String str2 = tasks[i-2].result();
2120            if (!str1.equals(str2)) {
2121                System.out.println("mismatch at " + i);
2122                System.out.println(str1);
2123                System.out.println(str2);
2124                errln("decimal format thread mismatch");
2125
2126                break;
2127            }
2128            str1 = str2;
2129        }
2130    }
2131
2132    @Test
2133    public void TestPerMill() {
2134        DecimalFormat fmt = new DecimalFormat("###.###\u2030");
2135        assertEquals("0.4857 x ###.###\u2030",
2136                "485.7\u2030", fmt.format(0.4857));
2137
2138        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.ENGLISH);
2139        sym.setPerMill('m');
2140        DecimalFormat fmt2 = new DecimalFormat("", sym);
2141        fmt2.applyLocalizedPattern("###.###m");
2142        assertEquals("0.4857 x ###.###m",
2143                "485.7m", fmt2.format(0.4857));
2144    }
2145
2146    @Test
2147    public void TestIllegalPatterns() {
2148        // Test cases:
2149        // Prefix with "-:" for illegal patterns
2150        // Prefix with "+:" for legal patterns
2151        String DATA[] = {
2152                // Unquoted special characters in the suffix are illegal
2153                "-:000.000|###",
2154                "+:000.000'|###'",
2155        };
2156        for (int i=0; i<DATA.length; ++i) {
2157            String pat=DATA[i];
2158            boolean valid = pat.charAt(0) == '+';
2159            pat = pat.substring(2);
2160            Exception e = null;
2161            try {
2162                // locale doesn't matter here
2163                new DecimalFormat(pat);
2164            } catch (IllegalArgumentException e1) {
2165                e = e1;
2166            } catch (IndexOutOfBoundsException e1) {
2167                e = e1;
2168            }
2169            String msg = (e==null) ? "success" : e.getMessage();
2170            if ((e==null) == valid) {
2171                logln("Ok: pattern \"" + pat + "\": " + msg);
2172            } else {
2173                errln("FAIL: pattern \"" + pat + "\" should have " +
2174                        (valid?"succeeded":"failed") + "; got " + msg);
2175            }
2176        }
2177    }
2178
2179    /**
2180     * Parse a CurrencyAmount using the given NumberFormat, with
2181     * the 'delim' character separating the number and the currency.
2182     */
2183    private static CurrencyAmount parseCurrencyAmount(String str, NumberFormat fmt,
2184            char delim)
2185                    throws ParseException {
2186        int i = str.indexOf(delim);
2187        return new CurrencyAmount(fmt.parse(str.substring(0,i)),
2188                Currency.getInstance(str.substring(i+1)));
2189    }
2190
2191    /**
2192     * Return an integer representing the next token from this
2193     * iterator.  The integer will be an index into the given list, or
2194     * -1 if there are no more tokens, or -2 if the token is not on
2195     * the list.
2196     */
2197    private static int keywordIndex(String tok) {
2198        for (int i=0; i<KEYWORDS.length; ++i) {
2199            if (tok.equals(KEYWORDS[i])) {
2200                return i;
2201            }
2202        }
2203        return -1;
2204    }
2205
2206    private static final String KEYWORDS[] = {
2207        /*0*/ "ref=", // <reference pattern to parse numbers>
2208        /*1*/ "loc=", // <locale for formats>
2209        /*2*/ "f:",   // <pattern or '-'> <number> <exp. string>
2210        /*3*/ "fp:",  // <pattern or '-'> <number> <exp. string> <exp. number>
2211        /*4*/ "rt:",  // <pattern or '-'> <(exp.) number> <(exp.) string>
2212        /*5*/ "p:",   // <pattern or '-'> <string> <exp. number>
2213        /*6*/ "perr:", // <pattern or '-'> <invalid string>
2214        /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
2215        /*8*/ "fpc:", // <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
2216        /*9*/ "strict=", // true or false
2217    };
2218
2219    @SuppressWarnings("resource")  // InputStream is will be closed by the ResourceReader.
2220    @Test
2221    public void TestCases() {
2222        String caseFileName = "NumberFormatTestCases.txt";
2223        java.io.InputStream is = NumberFormatTest.class.getResourceAsStream(caseFileName);
2224
2225        ResourceReader reader = new ResourceReader(is, caseFileName, "utf-8");
2226        TokenIterator tokens = new TokenIterator(reader);
2227
2228        Locale loc = new Locale("en", "US", "");
2229        DecimalFormat ref = null, fmt = null;
2230        MeasureFormat mfmt = null;
2231        String pat = null, str = null, mloc = null;
2232        boolean strict = false;
2233
2234        try {
2235            for (;;) {
2236                String tok = tokens.next();
2237                if (tok == null) {
2238                    break;
2239                }
2240                String where = "(" + tokens.getLineNumber() + ") ";
2241                int cmd = keywordIndex(tok);
2242                switch (cmd) {
2243                case 0:
2244                    // ref= <reference pattern>
2245                    ref = new DecimalFormat(tokens.next(),
2246                            new DecimalFormatSymbols(Locale.US));
2247                    ref.setParseStrict(strict);
2248                    logln("Setting reference pattern to:\t" + ref);
2249                    break;
2250                case 1:
2251                    // loc= <locale>
2252                    loc = LocaleUtility.getLocaleFromName(tokens.next());
2253                    pat = ((DecimalFormat) NumberFormat.getInstance(loc)).toPattern();
2254                    logln("Setting locale to:\t" + loc + ", \tand pattern to:\t" + pat);
2255                    break;
2256                case 2: // f:
2257                case 3: // fp:
2258                case 4: // rt:
2259                case 5: // p:
2260                    tok = tokens.next();
2261                    if (!tok.equals("-")) {
2262                        pat = tok;
2263                    }
2264                    try {
2265                        fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc));
2266                        fmt.setParseStrict(strict);
2267                    } catch (IllegalArgumentException iae) {
2268                        errln(where + "Pattern \"" + pat + '"');
2269                        iae.printStackTrace();
2270                        tokens.next(); // consume remaining tokens
2271                        //tokens.next();
2272                        if (cmd == 3) tokens.next();
2273                        continue;
2274                    }
2275                    str = null;
2276                    try {
2277                        if (cmd == 2 || cmd == 3 || cmd == 4) {
2278                            // f: <pattern or '-'> <number> <exp. string>
2279                            // fp: <pattern or '-'> <number> <exp. string> <exp. number>
2280                            // rt: <pattern or '-'> <number> <string>
2281                            String num = tokens.next();
2282                            str = tokens.next();
2283                            Number n = ref.parse(num);
2284                            assertEquals(where + '"' + pat + "\".format(" + num + ")",
2285                                    str, fmt.format(n));
2286                            if (cmd == 3) { // fp:
2287                                n = ref.parse(tokens.next());
2288                            }
2289                            if (cmd != 2) { // != f:
2290                                assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
2291                                        n, fmt.parse(str));
2292                            }
2293                        }
2294                        // p: <pattern or '-'> <string to parse> <exp. number>
2295                        else {
2296                            str = tokens.next();
2297                            String expstr = tokens.next();
2298                            Number parsed = fmt.parse(str);
2299                            Number exp = ref.parse(expstr);
2300                            assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
2301                                    exp, parsed);
2302                        }
2303                    } catch (ParseException e) {
2304                        errln(where + '"' + pat + "\".parse(\"" + str +
2305                                "\") threw an exception");
2306                        e.printStackTrace();
2307                    }
2308                    break;
2309                case 6:
2310                    // perr: <pattern or '-'> <invalid string>
2311                    errln("Under construction");
2312                    return;
2313                case 7:
2314                    // pat: <pattern> <exp. toPattern, or '-' or 'err'>
2315                    String testpat = tokens.next();
2316                    String exppat  = tokens.next();
2317                    boolean err    = exppat.equals("err");
2318                    if (testpat.equals("-")) {
2319                        if (err) {
2320                            errln("Invalid command \"pat: - err\" at " +  tokens.describePosition());
2321                            continue;
2322                        }
2323                        testpat = pat;
2324                    }
2325                    if (exppat.equals("-")) exppat = testpat;
2326                    try {
2327                        DecimalFormat f = null;
2328                        if (testpat == pat) { // [sic]
2329                            f = fmt;
2330                        } else {
2331                            f = new DecimalFormat(testpat);
2332                            f.setParseStrict(strict);
2333                        }
2334                        if (err) {
2335                            errln(where + "Invalid pattern \"" + testpat +
2336                                    "\" was accepted");
2337                        } else {
2338                            assertEquals(where + '"' + testpat + "\".toPattern()",
2339                                    exppat, f.toPattern());
2340                        }
2341                    } catch (IllegalArgumentException iae2) {
2342                        if (err) {
2343                            logln("Ok: " + where + "Invalid pattern \"" + testpat +
2344                                    "\" threw an exception");
2345                        } else {
2346                            errln(where + "Valid pattern \"" + testpat +
2347                                    "\" threw an exception");
2348                            iae2.printStackTrace();
2349                        }
2350                    }
2351                    break;
2352                case 8: // fpc:
2353                    tok = tokens.next();
2354                    if (!tok.equals("-")) {
2355                        mloc = tok;
2356                        ULocale l = new ULocale(mloc);
2357                        try {
2358                            mfmt = MeasureFormat.getCurrencyFormat(l);
2359                        } catch (IllegalArgumentException iae) {
2360                            errln(where + "Loc \"" + tok + '"');
2361                            iae.printStackTrace();
2362                            tokens.next(); // consume remaining tokens
2363                            tokens.next();
2364                            tokens.next();
2365                            continue;
2366                        }
2367                    }
2368                    str = null;
2369                    try {
2370                        // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
2371                        String currAmt = tokens.next();
2372                        str = tokens.next();
2373                        CurrencyAmount target = parseCurrencyAmount(currAmt, ref, '/');
2374                        String formatResult = mfmt.format(target);
2375                        assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
2376                                str, formatResult);
2377                        target = parseCurrencyAmount(tokens.next(), ref, '/');
2378                        CurrencyAmount parseResult = (CurrencyAmount) mfmt.parseObject(str);
2379                        assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
2380                                target, parseResult);
2381                    } catch (ParseException e) {
2382                        errln(where + '"' + pat + "\".parse(\"" + str +
2383                                "\") threw an exception");
2384                        e.printStackTrace();
2385                    }
2386                    break;
2387                case 9: // strict= true or false
2388                    strict = "true".equalsIgnoreCase(tokens.next());
2389                    logln("Setting strict to:\t" + strict);
2390                    break;
2391                case -1:
2392                    errln("Unknown command \"" + tok + "\" at " + tokens.describePosition());
2393                    return;
2394                }
2395            }
2396        } catch (java.io.IOException e) {
2397            throw new RuntimeException(e);
2398        } finally {
2399            try {
2400                reader.close();
2401            } catch (IOException ignored) {
2402            }
2403        }
2404    }
2405
2406    @Test
2407    public void TestFieldPositionDecimal() {
2408        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2409        nf.setPositivePrefix("FOO");
2410        nf.setPositiveSuffix("BA");
2411        StringBuffer buffer = new StringBuffer();
2412        FieldPosition fp = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
2413        nf.format(35.47, buffer, fp);
2414        assertEquals("35.47", "FOO35.47BA", buffer.toString());
2415        assertEquals("fp begin", 5, fp.getBeginIndex());
2416        assertEquals("fp end", 6, fp.getEndIndex());
2417    }
2418
2419    @Test
2420    public void TestFieldPositionInteger() {
2421        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2422        nf.setPositivePrefix("FOO");
2423        nf.setPositiveSuffix("BA");
2424        StringBuffer buffer = new StringBuffer();
2425        FieldPosition fp = new FieldPosition(NumberFormat.Field.INTEGER);
2426        nf.format(35.47, buffer, fp);
2427        assertEquals("35.47", "FOO35.47BA", buffer.toString());
2428        assertEquals("fp begin", 3, fp.getBeginIndex());
2429        assertEquals("fp end", 5, fp.getEndIndex());
2430    }
2431
2432    @Test
2433    public void TestFieldPositionFractionButInteger() {
2434        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2435        nf.setPositivePrefix("FOO");
2436        nf.setPositiveSuffix("BA");
2437        StringBuffer buffer = new StringBuffer();
2438        FieldPosition fp = new FieldPosition(NumberFormat.Field.FRACTION);
2439        nf.format(35, buffer, fp);
2440        assertEquals("35", "FOO35BA", buffer.toString());
2441        assertEquals("fp begin", 5, fp.getBeginIndex());
2442        assertEquals("fp end", 5, fp.getEndIndex());
2443    }
2444
2445    @Test
2446    public void TestFieldPositionFraction() {
2447        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2448        nf.setPositivePrefix("FOO");
2449        nf.setPositiveSuffix("BA");
2450        StringBuffer buffer = new StringBuffer();
2451        FieldPosition fp = new FieldPosition(NumberFormat.Field.FRACTION);
2452        nf.format(35.47, buffer, fp);
2453        assertEquals("35.47", "FOO35.47BA", buffer.toString());
2454        assertEquals("fp begin", 6, fp.getBeginIndex());
2455        assertEquals("fp end", 8, fp.getEndIndex());
2456    }
2457
2458    @Test
2459    public void TestFieldPositionCurrency() {
2460        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getCurrencyInstance(Locale.US);
2461        double amount = 35.47;
2462        double negAmount = -34.567;
2463        FieldPosition cp = new FieldPosition(NumberFormat.Field.CURRENCY);
2464
2465        StringBuffer buffer0 = new StringBuffer();
2466        nf.format(amount, buffer0, cp);
2467        assertEquals("$35.47", "$35.47", buffer0.toString());
2468        assertEquals("cp begin", 0, cp.getBeginIndex());
2469        assertEquals("cp end", 1, cp.getEndIndex());
2470
2471        StringBuffer buffer01 = new StringBuffer();
2472        nf.format(negAmount, buffer01, cp);
2473        assertEquals("-$34.57", "-$34.57", buffer01.toString());
2474        assertEquals("cp begin", 1, cp.getBeginIndex());
2475        assertEquals("cp end", 2, cp.getEndIndex());
2476
2477        nf.setCurrency(Currency.getInstance(Locale.FRANCE));
2478        StringBuffer buffer1 = new StringBuffer();
2479        nf.format(amount, buffer1, cp);
2480        assertEquals("€35.47", "€35.47", buffer1.toString());
2481        assertEquals("cp begin", 0, cp.getBeginIndex());
2482        assertEquals("cp end", 1, cp.getEndIndex());
2483
2484        nf.setCurrency(Currency.getInstance(new Locale("fr", "ch", "")));
2485        StringBuffer buffer2 = new StringBuffer();
2486        nf.format(amount, buffer2, cp);
2487        assertEquals("CHF35.47", "CHF35.47", buffer2.toString());
2488        assertEquals("cp begin", 0, cp.getBeginIndex());
2489        assertEquals("cp end", 3, cp.getEndIndex());
2490
2491        StringBuffer buffer20 = new StringBuffer();
2492        nf.format(negAmount, buffer20, cp);
2493        assertEquals("-CHF34.57", "-CHF34.57", buffer20.toString());
2494        assertEquals("cp begin", 1, cp.getBeginIndex());
2495        assertEquals("cp end", 4, cp.getEndIndex());
2496
2497        nf = (DecimalFormat) android.icu.text.NumberFormat.getCurrencyInstance(Locale.FRANCE);
2498        StringBuffer buffer3 = new StringBuffer();
2499        nf.format(amount, buffer3, cp);
2500        assertEquals("35,47 €", "35,47 €", buffer3.toString());
2501        assertEquals("cp begin", 6, cp.getBeginIndex());
2502        assertEquals("cp end", 7, cp.getEndIndex());
2503
2504        StringBuffer buffer4 = new StringBuffer();
2505        nf.format(negAmount, buffer4, cp);
2506        assertEquals("-34,57 €", "-34,57 €", buffer4.toString());
2507        assertEquals("cp begin", 7, cp.getBeginIndex());
2508        assertEquals("cp end", 8, cp.getEndIndex());
2509
2510        nf.setCurrency(Currency.getInstance(new Locale("fr", "ch")));
2511        StringBuffer buffer5 = new StringBuffer();
2512        nf.format(negAmount, buffer5, cp);
2513        assertEquals("-34,57 CHF", "-34,57 CHF", buffer5.toString());
2514        assertEquals("cp begin", 7, cp.getBeginIndex());
2515        assertEquals("cp end", 10, cp.getEndIndex());
2516
2517        NumberFormat plCurrencyFmt = NumberFormat.getInstance(new Locale("fr", "ch"), NumberFormat.PLURALCURRENCYSTYLE);
2518        StringBuffer buffer6 = new StringBuffer();
2519        plCurrencyFmt.format(negAmount, buffer6, cp);
2520        assertEquals("-34.57 francs suisses", "-34.57 francs suisses", buffer6.toString());
2521        assertEquals("cp begin", 7, cp.getBeginIndex());
2522        assertEquals("cp end", 21, cp.getEndIndex());
2523
2524        // Positive value with PLURALCURRENCYSTYLE.
2525        plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "ch"), NumberFormat.PLURALCURRENCYSTYLE);
2526        StringBuffer buffer7 = new StringBuffer();
2527        plCurrencyFmt.format(amount, buffer7, cp);
2528        assertEquals("35.47スイス フラン", "35.47スイス フラン", buffer7.toString());
2529        assertEquals("cp begin", 5, cp.getBeginIndex());
2530        assertEquals("cp end", 12, cp.getEndIndex());
2531
2532        // PLURALCURRENCYSTYLE for non-ASCII.
2533        plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "de"), NumberFormat.PLURALCURRENCYSTYLE);
2534        StringBuffer buffer8 = new StringBuffer();
2535        plCurrencyFmt.format(negAmount, buffer8, cp);
2536        assertEquals("-34.57ユーロ", "-34.57ユーロ", buffer8.toString());
2537        assertEquals("cp begin", 6, cp.getBeginIndex());
2538        assertEquals("cp end", 9, cp.getEndIndex());
2539
2540        nf = (DecimalFormat) android.icu.text.NumberFormat.getCurrencyInstance(Locale.JAPAN);
2541        nf.setCurrency(Currency.getInstance(new Locale("ja", "jp")));
2542        StringBuffer buffer9 = new StringBuffer();
2543        nf.format(negAmount, buffer9, cp);
2544        assertEquals("-¥35", "-¥35", buffer9.toString());
2545        assertEquals("cp begin", 1, cp.getBeginIndex());
2546        assertEquals("cp end", 2, cp.getEndIndex());
2547
2548        // Negative value with PLURALCURRENCYSTYLE.
2549        plCurrencyFmt = NumberFormat.getInstance(new Locale("ja", "ch"), NumberFormat.PLURALCURRENCYSTYLE);
2550        StringBuffer buffer10 = new StringBuffer();
2551        plCurrencyFmt.format(negAmount, buffer10, cp);
2552        assertEquals("-34.57スイス フラン", "-34.57スイス フラン", buffer10.toString());
2553        assertEquals("cp begin", 6, cp.getBeginIndex());
2554        assertEquals("cp end", 13, cp.getEndIndex());
2555
2556        // Nagative value with PLURALCURRENCYSTYLE, Arabic digits.
2557        nf = (DecimalFormat) android.icu.text.NumberFormat.getCurrencyInstance(new Locale("ar", "eg"));
2558        plCurrencyFmt = NumberFormat.getInstance(new Locale("ar", "eg"), NumberFormat.PLURALCURRENCYSTYLE);
2559        StringBuffer buffer11 = new StringBuffer();
2560        plCurrencyFmt.format(negAmount, buffer11, cp);
2561        assertEquals("؜-٣٤٫٥٧ جنيه مصري", "؜-٣٤٫٥٧ جنيه مصري", buffer11.toString());
2562        assertEquals("cp begin", 8, cp.getBeginIndex());
2563        assertEquals("cp end", 17, cp.getEndIndex());
2564    }
2565
2566    @Test
2567    public void TestRounding() {
2568        DecimalFormat nf = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2569        if (false) { // for debugging specific value
2570            nf.setRoundingMode(BigDecimal.ROUND_HALF_UP);
2571            checkRounding(nf, new BigDecimal("300.0300000000"), 0, new BigDecimal("0.020000000"));
2572        }
2573        // full tests
2574        int[] roundingIncrements = {1, 2, 5, 20, 50, 100};
2575        int[] testValues = {0, 300};
2576        for (int j = 0; j < testValues.length; ++j) {
2577            for (int mode = BigDecimal.ROUND_UP; mode < BigDecimal.ROUND_HALF_EVEN; ++mode) {
2578                nf.setRoundingMode(mode);
2579                for (int increment = 0; increment < roundingIncrements.length; ++increment) {
2580                    BigDecimal base = new BigDecimal(testValues[j]);
2581                    BigDecimal rInc = new BigDecimal(roundingIncrements[increment]);
2582                    checkRounding(nf,  base, 20, rInc);
2583                    rInc = new BigDecimal("1.000000000").divide(rInc);
2584                    checkRounding(nf,  base, 20, rInc);
2585                }
2586            }
2587        }
2588    }
2589
2590    @Test
2591    public void TestRoundingPattern() {
2592        class TestRoundingPatternItem {
2593            String     pattern;
2594            double     roundingIncrement;
2595            double     testCase;
2596            String     expected;
2597
2598            TestRoundingPatternItem(String pattern, double roundingIncrement, double testCase, String expected) {
2599                this.pattern = pattern;
2600                this.roundingIncrement = roundingIncrement;
2601                this.testCase = testCase;
2602                this.expected = expected;
2603            }
2604        };
2605
2606        TestRoundingPatternItem []tests = {
2607                new TestRoundingPatternItem("##0.65", 0.65, 1.234, "1.30"),
2608                new TestRoundingPatternItem("#50", 50.0, 1230, "1250")
2609        };
2610
2611        DecimalFormat df = (DecimalFormat) android.icu.text.NumberFormat.getInstance(ULocale.ENGLISH);
2612        String result;
2613        BigDecimal bd;
2614        for (int i = 0; i < tests.length; i++) {
2615            df.applyPattern(tests[i].pattern);
2616
2617            result = df.format(tests[i].testCase);
2618
2619            if (!tests[i].expected.equals(result)) {
2620                errln("String Pattern Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
2621            }
2622
2623            bd = new BigDecimal(tests[i].roundingIncrement);
2624
2625            df.setRoundingIncrement(bd);
2626
2627            result = df.format(tests[i].testCase);
2628
2629            if (!tests[i].expected.equals(result)) {
2630                errln("BigDecimal Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
2631            }
2632        }
2633    }
2634
2635    @Test
2636    public void TestBigDecimalRounding() {
2637        String figure = "50.000000004";
2638        Double dbl = new Double(figure);
2639        BigDecimal dec = new BigDecimal(figure);
2640
2641        DecimalFormat f = (DecimalFormat) NumberFormat.getInstance();
2642        f.applyPattern("00.00######");
2643
2644        assertEquals("double format", "50.00", f.format(dbl));
2645        assertEquals("bigdec format", "50.00", f.format(dec));
2646
2647        int maxFracDigits = f.getMaximumFractionDigits();
2648        BigDecimal roundingIncrement = new BigDecimal("1").movePointLeft(maxFracDigits);
2649
2650        f.setRoundingIncrement(roundingIncrement);
2651        f.setRoundingMode(BigDecimal.ROUND_DOWN);
2652        assertEquals("Rounding down", f.format(dbl), f.format(dec));
2653
2654        f.setRoundingIncrement(roundingIncrement);
2655        f.setRoundingMode(BigDecimal.ROUND_HALF_UP);
2656        assertEquals("Rounding half up", f.format(dbl), f.format(dec));
2657    }
2658
2659    void checkRounding(DecimalFormat nf, BigDecimal base, int iterations, BigDecimal increment) {
2660        nf.setRoundingIncrement(increment.toBigDecimal());
2661        BigDecimal lastParsed = new BigDecimal(Integer.MIN_VALUE); // used to make sure that rounding is monotonic
2662        for (int i = -iterations; i <= iterations; ++i) {
2663            BigDecimal iValue = base.add(increment.multiply(new BigDecimal(i)).movePointLeft(1));
2664            BigDecimal smallIncrement = new BigDecimal("0.00000001");
2665            if (iValue.signum() != 0) {
2666                smallIncrement.multiply(iValue); // scale unless zero
2667            }
2668            // we not only test the value, but some values in a small range around it.
2669            lastParsed = checkRound(nf, iValue.subtract(smallIncrement), lastParsed);
2670            lastParsed = checkRound(nf, iValue, lastParsed);
2671            lastParsed = checkRound(nf, iValue.add(smallIncrement), lastParsed);
2672        }
2673    }
2674
2675    private BigDecimal checkRound(DecimalFormat nf, BigDecimal iValue, BigDecimal lastParsed) {
2676        String formatedBigDecimal = nf.format(iValue);
2677        String formattedDouble = nf.format(iValue.doubleValue());
2678        if (!equalButForTrailingZeros(formatedBigDecimal, formattedDouble)) {
2679
2680            errln("Failure at: " + iValue + " (" + iValue.doubleValue() + ")"
2681                    + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
2682                            + ",\tRounding-increment: " + nf.getRoundingIncrement()
2683                            + ",\tdouble: " + formattedDouble
2684                            + ",\tBigDecimal: " + formatedBigDecimal);
2685
2686        } else {
2687            logln("Value: " + iValue
2688                    + ",\tRounding-mode: " + roundingModeNames[nf.getRoundingMode()]
2689                            + ",\tRounding-increment: " + nf.getRoundingIncrement()
2690                            + ",\tdouble: " + formattedDouble
2691                            + ",\tBigDecimal: " + formatedBigDecimal);
2692        }
2693        try {
2694            // Number should have compareTo(...)
2695            BigDecimal parsed = toBigDecimal(nf.parse(formatedBigDecimal));
2696            if (lastParsed.compareTo(parsed) > 0) {
2697                errln("Rounding wrong direction!: " + lastParsed + " > " + parsed);
2698            }
2699            lastParsed = parsed;
2700        } catch (ParseException e) {
2701            errln("Parse Failure with: " + formatedBigDecimal);
2702        }
2703        return lastParsed;
2704    }
2705
2706    static BigDecimal toBigDecimal(Number number) {
2707        return number instanceof BigDecimal ? (BigDecimal) number
2708                : number instanceof BigInteger ? new BigDecimal((BigInteger)number)
2709        : number instanceof java.math.BigDecimal ? new BigDecimal((java.math.BigDecimal)number)
2710                : number instanceof Double ? new BigDecimal(number.doubleValue())
2711        : number instanceof Float ? new BigDecimal(number.floatValue())
2712                : new BigDecimal(number.longValue());
2713    }
2714
2715    static String[] roundingModeNames = {
2716        "ROUND_UP", "ROUND_DOWN", "ROUND_CEILING", "ROUND_FLOOR",
2717        "ROUND_HALF_UP", "ROUND_HALF_DOWN", "ROUND_HALF_EVEN",
2718        "ROUND_UNNECESSARY"
2719    };
2720
2721    private static boolean equalButForTrailingZeros(String formatted1, String formatted2) {
2722        if (formatted1.length() == formatted2.length()) return formatted1.equals(formatted2);
2723        return stripFinalZeros(formatted1).equals(stripFinalZeros(formatted2));
2724    }
2725
2726    private static String stripFinalZeros(String formatted) {
2727        int len1 = formatted.length();
2728        char ch;
2729        while (len1 > 0 && ((ch = formatted.charAt(len1-1)) == '0' || ch == '.')) --len1;
2730        if (len1==1 && ((ch = formatted.charAt(len1-1)) == '-')) --len1;
2731        return formatted.substring(0,len1);
2732    }
2733
2734    //------------------------------------------------------------------
2735    // Support methods
2736    //------------------------------------------------------------------
2737
2738    // Format-Parse test
2739    public void expect2(NumberFormat fmt, Number n, String exp) {
2740        // Don't round-trip format test, since we explicitly do it
2741        expect(fmt, n, exp, false);
2742        expect(fmt, exp, n);
2743    }
2744    // Format-Parse test
2745    public void expect3(NumberFormat fmt, Number n, String exp) {
2746        // Don't round-trip format test, since we explicitly do it
2747        expect_rbnf(fmt, n, exp, false);
2748        expect_rbnf(fmt, exp, n);
2749    }
2750
2751    // Format-Parse test (convenience)
2752    public void expect2(NumberFormat fmt, double n, String exp) {
2753        expect2(fmt, new Double(n), exp);
2754    }
2755    // Format-Parse test (convenience)
2756    public void expect3(NumberFormat fmt, double n, String exp) {
2757        expect3(fmt, new Double(n), exp);
2758    }
2759
2760    // Format-Parse test (convenience)
2761    public void expect2(NumberFormat fmt, long n, String exp) {
2762        expect2(fmt, new Long(n), exp);
2763    }
2764    // Format-Parse test (convenience)
2765    public void expect3(NumberFormat fmt, long n, String exp) {
2766        expect3(fmt, new Long(n), exp);
2767    }
2768
2769    // Format test
2770    public void expect(NumberFormat fmt, Number n, String exp, boolean rt) {
2771        StringBuffer saw = new StringBuffer();
2772        FieldPosition pos = new FieldPosition(0);
2773        fmt.format(n, saw, pos);
2774        String pat = ((DecimalFormat)fmt).toPattern();
2775        if (saw.toString().equals(exp)) {
2776            logln("Ok   " + n + " x " +
2777                    pat + " = \"" +
2778                    saw + "\"");
2779            // We should be able to round-trip the formatted string =>
2780            // number => string (but not the other way around: number
2781            // => string => number2, might have number2 != number):
2782            if (rt) {
2783                try {
2784                    Number n2 = fmt.parse(exp);
2785                    StringBuffer saw2 = new StringBuffer();
2786                    fmt.format(n2, saw2, pos);
2787                    if (!saw2.toString().equals(exp)) {
2788                        errln("expect() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2789                                ", FAIL \"" + exp + "\" => " + n2 + " => \"" + saw2 + '"');
2790                    }
2791                } catch (ParseException e) {
2792                    errln("expect() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2793                            ", " + e.getMessage());
2794                    return;
2795                }
2796            }
2797        } else {
2798            errln("expect() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2799                    ", FAIL " + n + " x " + pat + " = \"" + saw + "\", expected \"" + exp + "\"");
2800        }
2801    }
2802    // Format test
2803    public void expect_rbnf(NumberFormat fmt, Number n, String exp, boolean rt) {
2804        StringBuffer saw = new StringBuffer();
2805        FieldPosition pos = new FieldPosition(0);
2806        fmt.format(n, saw, pos);
2807        if (saw.toString().equals(exp)) {
2808            logln("Ok   " + n + " = \"" +
2809                    saw + "\"");
2810            // We should be able to round-trip the formatted string =>
2811            // number => string (but not the other way around: number
2812            // => string => number2, might have number2 != number):
2813            if (rt) {
2814                try {
2815                    Number n2 = fmt.parse(exp);
2816                    StringBuffer saw2 = new StringBuffer();
2817                    fmt.format(n2, saw2, pos);
2818                    if (!saw2.toString().equals(exp)) {
2819                        errln("expect_rbnf() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2820                                ", FAIL \"" + exp + "\" => " + n2 + " => \"" + saw2 + '"');
2821                    }
2822                } catch (ParseException e) {
2823                    errln("expect_rbnf() format test rt, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2824                            ", " + e.getMessage());
2825                    return;
2826                }
2827            }
2828        } else {
2829            errln("expect_rbnf() format test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2830                    ", FAIL " + n + " = \"" + saw + "\", expected \"" + exp + "\"");
2831        }
2832    }
2833
2834    // Format test (convenience)
2835    public void expect(NumberFormat fmt, Number n, String exp) {
2836        expect(fmt, n, exp, true);
2837    }
2838
2839    // Format test (convenience)
2840    public void expect(NumberFormat fmt, double n, String exp) {
2841        expect(fmt, new Double(n), exp);
2842    }
2843
2844    // Format test (convenience)
2845    public void expect(NumberFormat fmt, long n, String exp) {
2846        expect(fmt, new Long(n), exp);
2847    }
2848
2849    // Parse test
2850    public void expect(NumberFormat fmt, String str, Number n) {
2851        Number num = null;
2852        try {
2853            num = fmt.parse(str);
2854        } catch (ParseException e) {
2855            errln(e.getMessage());
2856            return;
2857        }
2858        String pat = ((DecimalFormat)fmt).toPattern();
2859        // A little tricky here -- make sure Double(12345.0) and
2860        // Long(12345) match.
2861        if (num.equals(n) || num.doubleValue() == n.doubleValue()) {
2862            logln("Ok   \"" + str + "\" x " +
2863                    pat + " = " +
2864                    num);
2865        } else {
2866            errln("expect() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2867                    ", FAIL \"" + str + "\" x " + pat + " = " + num + ", expected " + n);
2868        }
2869    }
2870
2871    // Parse test
2872    public void expect_rbnf(NumberFormat fmt, String str, Number n) {
2873        Number num = null;
2874        try {
2875            num = fmt.parse(str);
2876        } catch (ParseException e) {
2877            errln(e.getMessage());
2878            return;
2879        }
2880        // A little tricky here -- make sure Double(12345.0) and
2881        // Long(12345) match.
2882        if (num.equals(n) || num.doubleValue() == n.doubleValue()) {
2883            logln("Ok   \"" + str + " = " +
2884                    num);
2885        } else {
2886            errln("expect_rbnf() parse test, locale " + fmt.getLocale(ULocale.VALID_LOCALE) +
2887                    ", FAIL \"" + str + " = " + num + ", expected " + n);
2888        }
2889    }
2890
2891    // Parse test (convenience)
2892    public void expect(NumberFormat fmt, String str, double n) {
2893        expect(fmt, str, new Double(n));
2894    }
2895
2896    // Parse test (convenience)
2897    public void expect(NumberFormat fmt, String str, long n) {
2898        expect(fmt, str, new Long(n));
2899    }
2900
2901    private void expectCurrency(NumberFormat nf, Currency curr,
2902            double value, String string) {
2903        DecimalFormat fmt = (DecimalFormat) nf;
2904        if (curr != null) {
2905            fmt.setCurrency(curr);
2906        }
2907        String s = fmt.format(value).replace('\u00A0', ' ');
2908
2909        if (s.equals(string)) {
2910            logln("Ok: " + value + " x " + curr + " => " + s);
2911        } else {
2912            errln("FAIL: " + value + " x " + curr + " => " + s +
2913                    ", expected " + string);
2914        }
2915    }
2916
2917    public void expectPad(DecimalFormat fmt, String pat, int pos) {
2918        expectPad(fmt, pat, pos, 0, (char)0);
2919    }
2920
2921    public void expectPad(DecimalFormat fmt, final String pat, int pos, int width, final char pad) {
2922        int apos = 0, awidth = 0;
2923        char apadStr;
2924        try {
2925            fmt.applyPattern(pat);
2926            apos = fmt.getPadPosition();
2927            awidth = fmt.getFormatWidth();
2928            apadStr = fmt.getPadCharacter();
2929        } catch (Exception e) {
2930            apos = -1;
2931            awidth = width;
2932            apadStr = pad;
2933        }
2934
2935        if (apos == pos && awidth == width && apadStr == pad) {
2936            logln("Ok   \"" + pat + "\" pos="
2937                    + apos + ((pos == -1) ? "" : " width=" + awidth + " pad=" + apadStr));
2938        } else {
2939            errln("FAIL \"" + pat + "\" pos=" + apos + " width="
2940                    + awidth + " pad=" + apadStr + ", expected "
2941                    + pos + " " + width + " " + pad);
2942        }
2943    }
2944
2945    public void expectPat(DecimalFormat fmt, final String exp) {
2946        String pat = fmt.toPattern();
2947        if (pat.equals(exp)) {
2948            logln("Ok   \"" + pat + "\"");
2949        } else {
2950            errln("FAIL \"" + pat + "\", expected \"" + exp + "\"");
2951        }
2952    }
2953
2954
2955    private void expectParseCurrency(NumberFormat fmt, Currency expected, String text) {
2956        ParsePosition pos = new ParsePosition(0);
2957        CurrencyAmount currencyAmount = fmt.parseCurrency(text, pos);
2958        assertTrue("Parse of " + text + " should have succeeded.", pos.getIndex() > 0);
2959        assertEquals("Currency should be correct.", expected, currencyAmount.getCurrency());
2960    }
2961
2962    @Test
2963    public void TestJB3832(){
2964        ULocale locale = new ULocale("pt_PT@currency=PTE");
2965        NumberFormat format = NumberFormat.getCurrencyInstance(locale);
2966        Currency curr = Currency.getInstance(locale);
2967        logln("\nName of the currency is: " + curr.getName(locale, Currency.LONG_NAME, new boolean[] {false}));
2968        CurrencyAmount cAmt = new CurrencyAmount(1150.50, curr);
2969        logln("CurrencyAmount object's hashCode is: " + cAmt.hashCode()); //cover hashCode
2970        String str = format.format(cAmt);
2971        String expected = "1,150$50\u00a0\u200b";
2972        if(!expected.equals(str)){
2973            errln("Did not get the expected output Expected: "+expected+" Got: "+ str);
2974        }
2975    }
2976
2977    @Test
2978    public void TestStrictParse() {
2979        String[] pass = {
2980                "0",           // single zero before end of text is not leading
2981                "0 ",          // single zero at end of number is not leading
2982                "0.",          // single zero before period (or decimal, it's ambiguous) is not leading
2983                "0,",          // single zero before comma (not group separator) is not leading
2984                "0.0",         // single zero before decimal followed by digit is not leading
2985                "0. ",         // same as above before period (or decimal) is not leading
2986                "0.100,5",     // comma stops parse of decimal (no grouping)
2987                ".00",         // leading decimal is ok, even with zeros
2988                "1234567",     // group separators are not required
2989                "12345, ",     // comma not followed by digit is not a group separator, but end of number
2990                "1,234, ",     // if group separator is present, group sizes must be appropriate
2991                "1,234,567",   // ...secondary too
2992                "0E",          // an exponent not followed by zero or digits is not an exponent
2993                "00",          // leading zero before zero - used to be error - see ticket #7913
2994                "012",         // leading zero before digit - used to be error - see ticket #7913
2995                "0,456",       // leading zero before group separator - used to be error - see ticket #7913
2996        };
2997        String[] fail = {
2998                "1,2",       // wrong number of digits after group separator
2999                ",0",        // leading group separator before zero
3000                ",1",        // leading group separator before digit
3001                ",.02",      // leading group separator before decimal
3002                "1,.02",     // group separator before decimal
3003                "1,,200",    // multiple group separators
3004                "1,45",      // wrong number of digits in primary group
3005                "1,45 that", // wrong number of digits in primary group
3006                "1,45.34",   // wrong number of digits in primary group
3007                "1234,567",  // wrong number of digits in secondary group
3008                "12,34,567", // wrong number of digits in secondary group
3009                "1,23,456,7890", // wrong number of digits in primary and secondary groups
3010        };
3011
3012        DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
3013        runStrictParseBatch(nf, pass, fail);
3014
3015        String[] scientificPass = {
3016                "0E2",      // single zero before exponent is ok
3017                "1234E2",   // any number of digits before exponent is ok
3018                "1,234E",   // an exponent string not followed by zero or digits is not an exponent
3019                "00E2",     // leading zeroes now allowed in strict mode - see ticket #
3020        };
3021        String[] scientificFail = {
3022                "1,234E2",  // group separators with exponent fail
3023        };
3024
3025        nf = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
3026        runStrictParseBatch(nf, scientificPass, scientificFail);
3027
3028        String[] mixedPass = {
3029                "12,34,567",
3030                "12,34,567,",
3031                "12,34,567, that",
3032                "12,34,567 that",
3033        };
3034        String[] mixedFail = {
3035                "12,34,56",
3036                "12,34,56,",
3037                "12,34,56, that ",
3038                "12,34,56 that",
3039        };
3040
3041        nf = new DecimalFormat("#,##,##0.#");
3042        runStrictParseBatch(nf, mixedPass, mixedFail);
3043    }
3044
3045    void runStrictParseBatch(DecimalFormat nf, String[] pass, String[] fail) {
3046        nf.setParseStrict(false);
3047        runStrictParseTests("should pass", nf, pass, true);
3048        runStrictParseTests("should also pass", nf, fail, true);
3049        nf.setParseStrict(true);
3050        runStrictParseTests("should still pass", nf, pass, true);
3051        runStrictParseTests("should fail", nf, fail, false);
3052    }
3053
3054    void runStrictParseTests(String msg, DecimalFormat nf, String[] tests, boolean pass) {
3055        logln("");
3056        logln("pattern: '" + nf.toPattern() + "'");
3057        logln(msg);
3058        for (int i = 0; i < tests.length; ++i) {
3059            String str = tests[i];
3060            ParsePosition pp = new ParsePosition(0);
3061            Number n = nf.parse(str, pp);
3062            String formatted = n != null ? nf.format(n) : "null";
3063            String err = pp.getErrorIndex() == -1 ? "" : "(error at " + pp.getErrorIndex() + ")";
3064            if ((err.length() == 0) != pass) {
3065                errln("'" + str + "' parsed '" +
3066                        str.substring(0, pp.getIndex()) +
3067                        "' returned " + n + " formats to '" +
3068                        formatted + "' " + err);
3069            } else {
3070                if (err.length() > 0) {
3071                    err = "got expected " + err;
3072                }
3073                logln("'" + str + "' parsed '" +
3074                        str.substring(0, pp.getIndex()) +
3075                        "' returned " + n + " formats to '" +
3076                        formatted + "' " + err);
3077            }
3078        }
3079    }
3080
3081    @Test
3082    public void TestJB5251(){
3083        //save default locale
3084        ULocale defaultLocale = ULocale.getDefault();
3085        ULocale.setDefault(new ULocale("qr_QR"));
3086        try {
3087            NumberFormat.getInstance();
3088        }
3089        catch (Exception e) {
3090            errln("Numberformat threw exception for non-existent locale. It should use the default.");
3091        }
3092        //reset default locale
3093        ULocale.setDefault(defaultLocale);
3094    }
3095
3096    @Test
3097    public void TestParseReturnType() {
3098        String[] defaultNonBigDecimals = {
3099                "123",      // Long
3100                "123.0",    // Long
3101                "0.0",      // Long
3102                "12345678901234567890"      // BigInteger
3103        };
3104
3105        String[] doubles = {
3106                "-0.0",
3107                "NaN",
3108                "\u221E"    // Infinity
3109        };
3110
3111        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
3112        DecimalFormat nf = new DecimalFormat("#.#", sym);
3113
3114        if (nf.isParseBigDecimal()) {
3115            errln("FAIL: isParseDecimal() must return false by default");
3116        }
3117
3118        // isParseBigDecimal() is false
3119        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
3120            try {
3121                Number n = nf.parse(defaultNonBigDecimals[i]);
3122                if (n instanceof BigDecimal) {
3123                    errln("FAIL: parse returns BigDecimal instance");
3124                }
3125            } catch (ParseException e) {
3126                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
3127            }
3128        }
3129        // parse results for doubls must be always Double
3130        for (int i = 0; i < doubles.length; i++) {
3131            try {
3132                Number n = nf.parse(doubles[i]);
3133                if (!(n instanceof Double)) {
3134                    errln("FAIL: parse does not return Double instance");
3135                }
3136            } catch (ParseException e) {
3137                errln("parse of '" + doubles[i] + "' threw exception: " + e);
3138            }
3139        }
3140
3141        // force this DecimalFormat to return BigDecimal
3142        nf.setParseBigDecimal(true);
3143        if (!nf.isParseBigDecimal()) {
3144            errln("FAIL: isParseBigDecimal() must return true");
3145        }
3146
3147        // isParseBigDecimal() is true
3148        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
3149            try {
3150                Number n = nf.parse(defaultNonBigDecimals[i]);
3151                if (!(n instanceof BigDecimal)) {
3152                    errln("FAIL: parse does not return BigDecimal instance");
3153                }
3154            } catch (ParseException e) {
3155                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
3156            }
3157        }
3158        // parse results for doubls must be always Double
3159        for (int i = 0; i < doubles.length; i++) {
3160            try {
3161                Number n = nf.parse(doubles[i]);
3162                if (!(n instanceof Double)) {
3163                    errln("FAIL: parse does not return Double instance");
3164                }
3165            } catch (ParseException e) {
3166                errln("parse of '" + doubles[i] + "' threw exception: " + e);
3167            }
3168        }
3169    }
3170
3171    @Test
3172    public void TestNonpositiveMultiplier() {
3173        DecimalFormat df = new DecimalFormat("0");
3174
3175        // test zero multiplier
3176
3177        try {
3178            df.setMultiplier(0);
3179
3180            // bad
3181            errln("DecimalFormat.setMultiplier(0) did not throw an IllegalArgumentException");
3182        } catch (IllegalArgumentException ex) {
3183            // good
3184        }
3185
3186        // test negative multiplier
3187
3188        try {
3189            df.setMultiplier(-1);
3190
3191            if (df.getMultiplier() != -1) {
3192                errln("DecimalFormat.setMultiplier(-1) did not change the multiplier to -1");
3193                return;
3194            }
3195
3196            // good
3197        } catch (IllegalArgumentException ex) {
3198            // bad
3199            errln("DecimalFormat.setMultiplier(-1) threw an IllegalArgumentException");
3200            return;
3201        }
3202
3203        expect(df, "1122.123", -1122.123);
3204        expect(df, "-1122.123", 1122.123);
3205        expect(df, "1.2", -1.2);
3206        expect(df, "-1.2", 1.2);
3207
3208        expect2(df, Long.MAX_VALUE, BigInteger.valueOf(Long.MAX_VALUE).negate().toString());
3209        expect2(df, Long.MIN_VALUE, BigInteger.valueOf(Long.MIN_VALUE).negate().toString());
3210        expect2(df, Long.MAX_VALUE / 2, BigInteger.valueOf(Long.MAX_VALUE / 2).negate().toString());
3211        expect2(df, Long.MIN_VALUE / 2, BigInteger.valueOf(Long.MIN_VALUE / 2).negate().toString());
3212
3213        expect2(df, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
3214        expect2(df, BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
3215
3216        expect2(df, java.math.BigDecimal.valueOf(Long.MAX_VALUE), java.math.BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
3217        expect2(df, java.math.BigDecimal.valueOf(Long.MIN_VALUE), java.math.BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
3218    }
3219
3220    @Test
3221    public void TestJB5358() {
3222        int numThreads = 10;
3223        String numstr = "12345";
3224        double expected = 12345;
3225        DecimalFormatSymbols sym = new DecimalFormatSymbols(Locale.US);
3226        DecimalFormat fmt = new DecimalFormat("#.#", sym);
3227        ArrayList errors = new ArrayList();
3228
3229        ParseThreadJB5358[] threads = new ParseThreadJB5358[numThreads];
3230        for (int i = 0; i < numThreads; i++) {
3231            threads[i] = new ParseThreadJB5358((DecimalFormat)fmt.clone(), numstr, expected, errors);
3232            threads[i].start();
3233        }
3234        for (int i = 0; i < numThreads; i++) {
3235            try {
3236                threads[i].join();
3237            } catch (InterruptedException ie) {
3238                ie.printStackTrace();
3239            }
3240        }
3241        if (errors.size() != 0) {
3242            StringBuffer errBuf = new StringBuffer();
3243            for (int i = 0; i < errors.size(); i++) {
3244                errBuf.append((String)errors.get(i));
3245                errBuf.append("\n");
3246            }
3247            errln("FAIL: " + errBuf);
3248        }
3249    }
3250
3251    static private class ParseThreadJB5358 extends Thread {
3252        private final DecimalFormat decfmt;
3253        private final String numstr;
3254        private final double expect;
3255        private final ArrayList errors;
3256
3257        public ParseThreadJB5358(DecimalFormat decfmt, String numstr, double expect, ArrayList errors) {
3258            this.decfmt = decfmt;
3259            this.numstr = numstr;
3260            this.expect = expect;
3261            this.errors = errors;
3262        }
3263
3264        @Override
3265        public void run() {
3266            for (int i = 0; i < 10000; i++) {
3267                try {
3268                    Number n = decfmt.parse(numstr);
3269                    if (n.doubleValue() != expect) {
3270                        synchronized(errors) {
3271                            errors.add(new String("Bad parse result - expected:" + expect + " actual:" + n.doubleValue()));
3272                        }
3273                    }
3274                } catch (Throwable t) {
3275                    synchronized(errors) {
3276                        errors.add(new String(t.getClass().getName() + " - " + t.getMessage()));
3277                    }
3278                }
3279            }
3280        }
3281    }
3282
3283    @Test
3284    public void TestSetCurrency() {
3285        DecimalFormatSymbols decf1 = DecimalFormatSymbols.getInstance(ULocale.US);
3286        DecimalFormatSymbols decf2 = DecimalFormatSymbols.getInstance(ULocale.US);
3287        decf2.setCurrencySymbol("UKD");
3288        DecimalFormat format1 = new DecimalFormat("000.000", decf1);
3289        DecimalFormat format2 = new DecimalFormat("000.000", decf2);
3290        Currency euro = Currency.getInstance("EUR");
3291        format1.setCurrency(euro);
3292        format2.setCurrency(euro);
3293        assertEquals("Reset with currency symbol", format1, format2);
3294    }
3295
3296    /*
3297     * Testing the method public StringBuffer format(Object number, ...)
3298     */
3299    @Test
3300    public void TestFormat() {
3301        NumberFormat nf = NumberFormat.getInstance();
3302        StringBuffer sb = new StringBuffer("dummy");
3303        FieldPosition fp = new FieldPosition(0);
3304
3305        // Tests when "if (number instanceof Long)" is true
3306        try {
3307            nf.format(new Long("0"), sb, fp);
3308        } catch (Exception e) {
3309            errln("NumberFormat.format(Object number, ...) was not suppose to "
3310                    + "return an exception for a Long object. Error: " + e);
3311        }
3312
3313        // Tests when "else if (number instanceof BigInteger)" is true
3314        try {
3315            nf.format((Object)new BigInteger("0"), sb, fp);
3316        } catch (Exception e) {
3317            errln("NumberFormat.format(Object number, ...) was not suppose to "
3318                    + "return an exception for a BigInteger object. Error: " + e);
3319        }
3320
3321        // Tests when "else if (number instanceof java.math.BigDecimal)" is true
3322        try {
3323            nf.format((Object)new java.math.BigDecimal("0"), sb, fp);
3324        } catch (Exception e) {
3325            errln("NumberFormat.format(Object number, ...) was not suppose to "
3326                    + "return an exception for a java.math.BigDecimal object. Error: " + e);
3327        }
3328
3329        // Tests when "else if (number instanceof android.icu.math.BigDecimal)" is true
3330        try {
3331            nf.format((Object)new android.icu.math.BigDecimal("0"), sb, fp);
3332        } catch (Exception e) {
3333            errln("NumberFormat.format(Object number, ...) was not suppose to "
3334                    + "return an exception for a android.icu.math.BigDecimal object. Error: " + e);
3335        }
3336
3337        // Tests when "else if (number instanceof CurrencyAmount)" is true
3338        try {
3339            CurrencyAmount ca = new CurrencyAmount(0.0, Currency.getInstance(new ULocale("en_US")));
3340            nf.format((Object)ca, sb, fp);
3341        } catch (Exception e) {
3342            errln("NumberFormat.format(Object number, ...) was not suppose to "
3343                    + "return an exception for a CurrencyAmount object. Error: " + e);
3344        }
3345
3346        // Tests when "else if (number instanceof Number)" is true
3347        try {
3348            nf.format(0.0, sb, fp);
3349        } catch (Exception e) {
3350            errln("NumberFormat.format(Object number, ...) was not suppose to "
3351                    + "to return an exception for a Number object. Error: " + e);
3352        }
3353
3354        // Tests when "else" is true
3355        try {
3356            nf.format(new Object(), sb, fp);
3357            errln("NumberFormat.format(Object number, ...) was suppose to "
3358                    + "return an exception for an invalid object.");
3359        } catch (Exception e) {
3360        }
3361
3362        try {
3363            nf.format(new String("dummy"), sb, fp);
3364            errln("NumberFormat.format(Object number, ...) was suppose to "
3365                    + "return an exception for an invalid object.");
3366        } catch (Exception e) {
3367        }
3368    }
3369
3370    /*
3371     * Coverage tests for the implementation of abstract format methods not being called otherwise
3372     */
3373    public void TestFormatAbstractImplCoverage() {
3374        NumberFormat df = DecimalFormat.getInstance(Locale.ENGLISH);
3375        NumberFormat cdf = CompactDecimalFormat.getInstance(Locale.ENGLISH, CompactDecimalFormat.CompactStyle.SHORT);
3376        NumberFormat rbf = new RuleBasedNumberFormat(ULocale.ENGLISH, RuleBasedNumberFormat.SPELLOUT);
3377
3378        /*
3379         *  Test  NumberFormat.format(BigDecimal,StringBuffer,FieldPosition)
3380         */
3381        StringBuffer sb = new StringBuffer();
3382        String result = df.format(new BigDecimal(2000.43), sb, new FieldPosition(0)).toString();
3383        if (!"2,000.43".equals(result)) {
3384            errln("DecimalFormat failed. Expected: 2,000.43 - Actual: " + result);
3385        }
3386
3387        sb.delete(0, sb.length());
3388        result = cdf.format(new BigDecimal(2000.43), sb, new FieldPosition(0)).toString();
3389        if (!"2K".equals(result)) {
3390            errln("DecimalFormat failed. Expected: 2K - Actual: " + result);
3391        }
3392
3393        sb.delete(0, sb.length());
3394        result = rbf.format(new BigDecimal(2000.43), sb, new FieldPosition(0)).toString();
3395        if (!"two thousand point four three".equals(result)) {
3396            errln("DecimalFormat failed. Expected: 'two thousand point four three' - Actual: '" + result + "'");
3397        }
3398    }
3399
3400    /*
3401     * Tests the method public final static NumberFormat getInstance(int style) public static NumberFormat
3402     * getInstance(Locale inLocale, int style) public static NumberFormat getInstance(ULocale desiredLocale, int choice)
3403     */
3404    @Test
3405    public void TestGetInstance() {
3406        // Tests "public final static NumberFormat getInstance(int style)"
3407        int maxStyle = NumberFormat.STANDARDCURRENCYSTYLE;
3408
3409        int[] invalid_cases = { NumberFormat.NUMBERSTYLE - 1, NumberFormat.NUMBERSTYLE - 2,
3410                maxStyle + 1, maxStyle + 2 };
3411
3412        for (int i = NumberFormat.NUMBERSTYLE; i < maxStyle; i++) {
3413            try {
3414                NumberFormat.getInstance(i);
3415            } catch (Exception e) {
3416                errln("NumberFormat.getInstance(int style) was not suppose to "
3417                        + "return an exception for passing value of " + i);
3418            }
3419        }
3420
3421        for (int i = 0; i < invalid_cases.length; i++) {
3422            try {
3423                NumberFormat.getInstance(invalid_cases[i]);
3424                errln("NumberFormat.getInstance(int style) was suppose to "
3425                        + "return an exception for passing value of " + invalid_cases[i]);
3426            } catch (Exception e) {
3427            }
3428        }
3429
3430        // Tests "public static NumberFormat getInstance(Locale inLocale, int style)"
3431        String[] localeCases = { "en_US", "fr_FR", "de_DE", "jp_JP" };
3432
3433        for (int i = NumberFormat.NUMBERSTYLE; i < maxStyle; i++) {
3434            for (int j = 0; j < localeCases.length; j++) {
3435                try {
3436                    NumberFormat.getInstance(new Locale(localeCases[j]), i);
3437                } catch (Exception e) {
3438                    errln("NumberFormat.getInstance(Locale inLocale, int style) was not suppose to "
3439                            + "return an exception for passing value of " + localeCases[j] + ", " + i);
3440                }
3441            }
3442        }
3443
3444        // Tests "public static NumberFormat getInstance(ULocale desiredLocale, int choice)"
3445        // Tests when "if (choice < NUMBERSTYLE || choice > PLURALCURRENCYSTYLE)" is true
3446        for (int i = 0; i < invalid_cases.length; i++) {
3447            try {
3448                NumberFormat.getInstance((ULocale) null, invalid_cases[i]);
3449                errln("NumberFormat.getInstance(ULocale inLocale, int choice) was not suppose to "
3450                        + "return an exception for passing value of " + invalid_cases[i]);
3451            } catch (Exception e) {
3452            }
3453        }
3454    }
3455
3456    /*
3457     * Tests the class public static abstract class NumberFormatFactory
3458     */
3459    @Test
3460    public void TestNumberFormatFactory() {
3461        /*
3462         * The following class allows the method public NumberFormat createFormat(Locale loc, int formatType) to be
3463         * tested.
3464         */
3465        class TestFactory extends NumberFormatFactory {
3466            @Override
3467            public Set<String> getSupportedLocaleNames() {
3468                return null;
3469            }
3470
3471            @Override
3472            public NumberFormat createFormat(ULocale loc, int formatType) {
3473                return null;
3474            }
3475        }
3476
3477        /*
3478         * The following class allows the method public NumberFormat createFormat(ULocale loc, int formatType) to be
3479         * tested.
3480         */
3481        class TestFactory1 extends NumberFormatFactory {
3482            @Override
3483            public Set<String> getSupportedLocaleNames() {
3484                return null;
3485            }
3486
3487            @Override
3488            public NumberFormat createFormat(Locale loc, int formatType) {
3489                return null;
3490            }
3491        }
3492
3493        TestFactory tf = new TestFactory();
3494        TestFactory1 tf1 = new TestFactory1();
3495
3496        /*
3497         * Tests the method public boolean visible()
3498         */
3499        if (tf.visible() != true) {
3500            errln("NumberFormatFactory.visible() was suppose to return true.");
3501        }
3502
3503        /*
3504         * Tests the method public NumberFormat createFormat(Locale loc, int formatType)
3505         */
3506        if (tf.createFormat(new Locale(""), 0) != null) {
3507            errln("NumberFormatFactory.createFormat(Locale loc, int formatType) " + "was suppose to return null");
3508        }
3509
3510        /*
3511         * Tests the method public NumberFormat createFormat(ULocale loc, int formatType)
3512         */
3513        if (tf1.createFormat(new ULocale(""), 0) != null) {
3514            errln("NumberFormatFactory.createFormat(ULocale loc, int formatType) " + "was suppose to return null");
3515        }
3516    }
3517
3518    /*
3519     * Tests the class public static abstract class SimpleNumberFormatFactory extends NumberFormatFactory
3520     */
3521    @Test
3522    public void TestSimpleNumberFormatFactory() {
3523        class TestSimpleNumberFormatFactory extends SimpleNumberFormatFactory {
3524            /*
3525             * Tests the method public SimpleNumberFormatFactory(Locale locale)
3526             */
3527            TestSimpleNumberFormatFactory() {
3528                super(new Locale(""));
3529            }
3530        }
3531        @SuppressWarnings("unused")
3532        TestSimpleNumberFormatFactory tsnff = new TestSimpleNumberFormatFactory();
3533    }
3534
3535    /*
3536     * Tests the method public static ULocale[] getAvailableLocales()
3537     */
3538    @SuppressWarnings("static-access")
3539    @Test
3540    public void TestGetAvailableLocales() {
3541        // Tests when "if (shim == null)" is true
3542        @SuppressWarnings("serial")
3543        class TestGetAvailableLocales extends NumberFormat {
3544            @Override
3545            public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
3546                return null;
3547            }
3548
3549            @Override
3550            public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
3551                return null;
3552            }
3553
3554            @Override
3555            public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
3556                return null;
3557            }
3558
3559            @Override
3560            public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
3561                return null;
3562            }
3563
3564            @Override
3565            public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
3566                return null;
3567            }
3568
3569            @Override
3570            public Number parse(String text, ParsePosition parsePosition) {
3571                return null;
3572            }
3573        }
3574
3575        try {
3576            TestGetAvailableLocales test = new TestGetAvailableLocales();
3577            test.getAvailableLocales();
3578        } catch (Exception e) {
3579            errln("NumberFormat.getAvailableLocales() was not suppose to "
3580                    + "return an exception when getting getting available locales.");
3581        }
3582    }
3583
3584    /*
3585     * Tests the method public void setMinimumIntegerDigits(int newValue)
3586     */
3587    @Test
3588    public void TestSetMinimumIntegerDigits() {
3589        NumberFormat nf = NumberFormat.getInstance();
3590        // For valid array, it is displayed as {min value, max value}
3591        // Tests when "if (minimumIntegerDigits > maximumIntegerDigits)" is true
3592        int[][] cases = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 2, 0 }, { 2, 1 }, { 10, 0 } };
3593        int[] expectedMax = { 0, 1, 1, 2, 2, 10 };
3594        if (cases.length != expectedMax.length) {
3595            errln("Can't continue test case method TestSetMinimumIntegerDigits "
3596                    + "since the test case arrays are unequal.");
3597        } else {
3598            for (int i = 0; i < cases.length; i++) {
3599                nf.setMaximumIntegerDigits(cases[i][1]);
3600                nf.setMinimumIntegerDigits(cases[i][0]);
3601                if (nf.getMaximumIntegerDigits() != expectedMax[i]) {
3602                    errln("NumberFormat.setMinimumIntegerDigits(int newValue "
3603                            + "did not return an expected result for parameter " + cases[i][1] + " and " + cases[i][0]
3604                                    + " and expected " + expectedMax[i] + " but got " + nf.getMaximumIntegerDigits());
3605                }
3606            }
3607        }
3608    }
3609
3610    /*
3611     * Tests the method public int getRoundingMode() public void setRoundingMode(int roundingMode)
3612     */
3613    @Test
3614    public void TestRoundingMode() {
3615        @SuppressWarnings("serial")
3616        class TestRoundingMode extends NumberFormat {
3617            @Override
3618            public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
3619                return null;
3620            }
3621
3622            @Override
3623            public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
3624                return null;
3625            }
3626
3627            @Override
3628            public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
3629                return null;
3630            }
3631
3632            @Override
3633            public StringBuffer format(java.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
3634                return null;
3635            }
3636
3637            @Override
3638            public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
3639                return null;
3640            }
3641
3642            @Override
3643            public Number parse(String text, ParsePosition parsePosition) {
3644                return null;
3645            }
3646        }
3647        TestRoundingMode tgrm = new TestRoundingMode();
3648
3649        // Tests the function 'public void setRoundingMode(int roundingMode)'
3650        try {
3651            tgrm.setRoundingMode(0);
3652            errln("NumberFormat.setRoundingMode(int) was suppose to return an exception");
3653        } catch (Exception e) {
3654        }
3655
3656        // Tests the function 'public int getRoundingMode()'
3657        try {
3658            tgrm.getRoundingMode();
3659            errln("NumberFormat.getRoundingMode() was suppose to return an exception");
3660        } catch (Exception e) {
3661        }
3662    }
3663
3664    /*
3665     * Testing lenient decimal/grouping separator parsing
3666     */
3667    @Test
3668    public void TestLenientSymbolParsing() {
3669        DecimalFormat fmt = new DecimalFormat();
3670        DecimalFormatSymbols sym = new DecimalFormatSymbols();
3671
3672        expect(fmt, "12\u300234", 12.34);
3673
3674        // Ticket#7345 - case 1
3675        // Even strict parsing, the decimal separator set in the symbols
3676        // should be successfully parsed.
3677
3678        sym.setDecimalSeparator('\u3002');
3679
3680        // non-strict
3681        fmt.setDecimalFormatSymbols(sym);
3682
3683        // strict - failed before the fix for #7345
3684        fmt.setParseStrict(true);
3685        expect(fmt, "23\u300245", 23.45);
3686        fmt.setParseStrict(false);
3687
3688
3689        // Ticket#7345 - case 2
3690        // Decimal separator variants other than DecimalFormatSymbols.decimalSeparator
3691        // should not hide the grouping separator DecimalFormatSymbols.groupingSeparator.
3692        sym.setDecimalSeparator('.');
3693        sym.setGroupingSeparator(',');
3694        fmt.setDecimalFormatSymbols(sym);
3695
3696        expect(fmt, "1,234.56", 1234.56);
3697
3698        sym.setGroupingSeparator('\uFF61');
3699        fmt.setDecimalFormatSymbols(sym);
3700
3701        expect(fmt, "2\uFF61345.67", 2345.67);
3702
3703        // Ticket#7128
3704        //
3705        sym.setGroupingSeparator(',');
3706        fmt.setDecimalFormatSymbols(sym);
3707
3708        String skipExtSepParse = ICUConfig.get("android.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false");
3709        if (skipExtSepParse.equals("true")) {
3710            // When the property SkipExtendedSeparatorParsing is true,
3711            // DecimalFormat does not use the extended equivalent separator
3712            // data and only uses the one in DecimalFormatSymbols.
3713            expect(fmt, "23 456", 23);
3714        } else {
3715            // Lenient separator parsing is enabled by default.
3716            // A space character below is interpreted as a
3717            // group separator, even ',' is used as grouping
3718            // separator in the symbols.
3719            expect(fmt, "12 345", 12345);
3720        }
3721    }
3722
3723    /*
3724     * Testing currency driven max/min fraction digits problem
3725     * reported by ticket#7282
3726     */
3727    @Test
3728    public void TestCurrencyFractionDigits() {
3729        double value = 99.12345;
3730
3731        // Create currency instance
3732        NumberFormat cfmt  = NumberFormat.getCurrencyInstance(new ULocale("ja_JP"));
3733        String text1 = cfmt.format(value);
3734
3735        // Reset the same currency and format the test value again
3736        cfmt.setCurrency(cfmt.getCurrency());
3737        String text2 = cfmt.format(value);
3738
3739        // output1 and output2 must be identical
3740        if (!text1.equals(text2)) {
3741            errln("NumberFormat.format() should return the same result - text1="
3742                    + text1 + " text2=" + text2);
3743        }
3744    }
3745
3746    /*
3747     * Testing rounding to negative zero problem
3748     * reported by ticket#7609
3749     */
3750    @Test
3751    public void TestNegZeroRounding() {
3752
3753        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
3754        df.setRoundingMode(MathContext.ROUND_HALF_UP);
3755        df.setMinimumFractionDigits(1);
3756        df.setMaximumFractionDigits(1);
3757        String text1 = df.format(-0.01);
3758
3759        df.setRoundingIncrement(0.1);
3760        String text2 = df.format(-0.01);
3761
3762        // output1 and output2 must be identical
3763        if (!text1.equals(text2)) {
3764            errln("NumberFormat.format() should return the same result - text1="
3765                    + text1 + " text2=" + text2);
3766        }
3767
3768    }
3769
3770    @Test
3771    public void TestCurrencyAmountCoverage() {
3772        CurrencyAmount ca, cb;
3773
3774        try {
3775            ca = new CurrencyAmount(null, null);
3776            errln("NullPointerException should have been thrown.");
3777        } catch (NullPointerException ex) {
3778        }
3779        try {
3780            ca = new CurrencyAmount(new Integer(0), null);
3781            errln("NullPointerException should have been thrown.");
3782        } catch (NullPointerException ex) {
3783        }
3784
3785        ca = new CurrencyAmount(new Integer(0), Currency.getInstance(new ULocale("ja_JP")));
3786        cb = new CurrencyAmount(new Integer(1), Currency.getInstance(new ULocale("ja_JP")));
3787        if (ca.equals(null)) {
3788            errln("Comparison should return false.");
3789        }
3790        if (!ca.equals(ca)) {
3791            errln("Comparision should return true.");
3792        }
3793        if (ca.equals(cb)) {
3794            errln("Comparison should return false.");
3795        }
3796    }
3797
3798    @Test
3799    public void TestExponentParse() {
3800        ParsePosition parsePos = new ParsePosition(0);
3801        DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
3802        DecimalFormat fmt = new DecimalFormat("#####", symbols);
3803        Number result = fmt.parse("5.06e-27", parsePos);
3804        if ( result.doubleValue() != 5.06E-27 || parsePos.getIndex() != 8) {
3805            errln("ERROR: ERROR: parse failed - expected 5.06E-27, 8; got " + result.doubleValue() + ", " + parsePos.getIndex());
3806        }
3807    }
3808
3809    @Test
3810    public void TestExplicitParents() {
3811        // We use these for testing because decimal and grouping separators will be inherited from es_419
3812        // starting with CLDR 2.0
3813        String[] DATA = {
3814                "es", "CO", "", "1.250,75",
3815                "es", "ES", "", "1.250,75",
3816                "es", "GQ", "", "1.250,75",
3817                "es", "MX", "", "1,250.75",
3818                "es", "US", "", "1,250.75",
3819                "es", "VE", "", "1.250,75",
3820
3821        };
3822
3823        for (int i=0; i<DATA.length; i+=4) {
3824            Locale locale = new Locale(DATA[i], DATA[i+1], DATA[i+2]);
3825            NumberFormat fmt = NumberFormat.getInstance(locale);
3826            String s = fmt.format(1250.75);
3827            if (s.equals(DATA[i+3])) {
3828                logln("Ok: 1250.75 x " + locale + " => " + s);
3829            } else {
3830                errln("FAIL: 1250.75 x " + locale + " => " + s +
3831                        ", expected " + DATA[i+3]);
3832            }
3833        }
3834    }
3835
3836    /*
3837     * Test case for #9240
3838     * ICU4J 49.1 DecimalFormat did not clone the internal object holding
3839     * formatted text attribute information properly. Therefore, DecimalFormat
3840     * created by cloning may return incorrect results or may throw an exception
3841     * when formatToCharacterIterator is invoked from multiple threads.
3842     */
3843    @Test
3844    public void TestFormatToCharacterIteratorThread() {
3845        final int COUNT = 10;
3846
3847        DecimalFormat fmt1 = new DecimalFormat("#0");
3848        DecimalFormat fmt2 = (DecimalFormat)fmt1.clone();
3849
3850        int[] res1 = new int[COUNT];
3851        int[] res2 = new int[COUNT];
3852
3853        Thread t1 = new Thread(new FormatCharItrTestThread(fmt1, 1, res1));
3854        Thread t2 = new Thread(new FormatCharItrTestThread(fmt2, 100, res2));
3855
3856        t1.start();
3857        t2.start();
3858
3859        try {
3860            t1.join();
3861            t2.join();
3862        } catch (InterruptedException e) {
3863            //TODO
3864        }
3865
3866        int val1 = res1[0];
3867        int val2 = res2[0];
3868
3869        for (int i = 0; i < COUNT; i++) {
3870            if (res1[i] != val1) {
3871                errln("Inconsistent first run limit in test thread 1");
3872            }
3873            if (res2[i] != val2) {
3874                errln("Inconsistent first run limit in test thread 2");
3875            }
3876        }
3877    }
3878
3879    @Test
3880    public void TestParseMaxDigits() {
3881        DecimalFormat fmt = new DecimalFormat();
3882        String number = "100000000000";
3883        int newParseMax = number.length() - 1;
3884
3885        fmt.setParseMaxDigits(-1);
3886
3887        /* Default value is 1000 */
3888        if (fmt.getParseMaxDigits() != 1000) {
3889            errln("Fail valid value checking in setParseMaxDigits.");
3890        }
3891
3892        try {
3893            if (fmt.parse(number).doubleValue() == Float.POSITIVE_INFINITY) {
3894                errln("Got Infinity but should NOT when parsing number: " + number);
3895            }
3896
3897            fmt.setParseMaxDigits(newParseMax);
3898
3899            if (fmt.parse(number).doubleValue() != Float.POSITIVE_INFINITY) {
3900                errln("Did not get Infinity but should when parsing number: " + number);
3901            }
3902        } catch (ParseException ex) {
3903
3904        }
3905    }
3906
3907    private static class FormatCharItrTestThread implements Runnable {
3908        private final NumberFormat fmt;
3909        private final int num;
3910        private final int[] result;
3911
3912        FormatCharItrTestThread(NumberFormat fmt, int num, int[] result) {
3913            this.fmt = fmt;
3914            this.num = num;
3915            this.result = result;
3916        }
3917
3918        @Override
3919        public void run() {
3920            for (int i = 0; i < result.length; i++) {
3921                AttributedCharacterIterator acitr = fmt.formatToCharacterIterator(num);
3922                acitr.first();
3923                result[i] = acitr.getRunLimit();
3924            }
3925        }
3926    }
3927
3928    @Test
3929    public void TestRoundingBehavior() {
3930        final Object[][] TEST_CASES = {
3931                {
3932                    ULocale.US,                             // ULocale - null for default locale
3933                    "#.##",                                 // Pattern
3934                    Integer.valueOf(BigDecimal.ROUND_DOWN), // Rounding Mode or null (implicit)
3935                    Double.valueOf(0.0d),                   // Rounding increment, Double or BigDecimal, or null (implicit)
3936                    Double.valueOf(123.4567d),              // Input value, Long, Double, BigInteger or BigDecimal
3937                    "123.45"                                // Expected result, null for exception
3938                },
3939                {
3940                    ULocale.US,
3941                    "#.##",
3942                    null,
3943                    Double.valueOf(0.1d),
3944                    Double.valueOf(123.4567d),
3945                    "123.5"
3946                },
3947                {
3948                    ULocale.US,
3949                    "#.##",
3950                    Integer.valueOf(BigDecimal.ROUND_DOWN),
3951                    Double.valueOf(0.1d),
3952                    Double.valueOf(123.4567d),
3953                    "123.4"
3954                },
3955                {
3956                    ULocale.US,
3957                    "#.##",
3958                    Integer.valueOf(BigDecimal.ROUND_UNNECESSARY),
3959                    null,
3960                    Double.valueOf(123.4567d),
3961                    null
3962                },
3963                {
3964                    ULocale.US,
3965                    "#.##",
3966                    Integer.valueOf(BigDecimal.ROUND_DOWN),
3967                    null,
3968                    Long.valueOf(1234),
3969                    "1234"
3970                },
3971        };
3972
3973        int testNum = 1;
3974
3975        for (Object[] testCase : TEST_CASES) {
3976            // 0: locale
3977            // 1: pattern
3978            ULocale locale = testCase[0] == null ? ULocale.getDefault() : (ULocale)testCase[0];
3979            String pattern = (String)testCase[1];
3980
3981            DecimalFormat fmt = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(locale));
3982
3983            // 2: rounding mode
3984            Integer roundingMode = null;
3985            if (testCase[2] != null) {
3986                roundingMode = (Integer)testCase[2];
3987                fmt.setRoundingMode(roundingMode);
3988            }
3989
3990            // 3: rounding increment
3991            if (testCase[3] != null) {
3992                if (testCase[3] instanceof Double) {
3993                    fmt.setRoundingIncrement((Double)testCase[3]);
3994                } else if (testCase[3] instanceof BigDecimal) {
3995                    fmt.setRoundingIncrement((BigDecimal)testCase[3]);
3996                } else if (testCase[3] instanceof java.math.BigDecimal) {
3997                    fmt.setRoundingIncrement((java.math.BigDecimal)testCase[3]);
3998                }
3999            }
4000
4001            // 4: input number
4002            String s = null;
4003            boolean bException = false;
4004            try {
4005                s = fmt.format(testCase[4]);
4006            } catch (ArithmeticException e) {
4007                bException = true;
4008            }
4009
4010            if (bException) {
4011                if (testCase[5] != null) {
4012                    errln("Test case #" + testNum + ": ArithmeticException was thrown.");
4013                }
4014            } else {
4015                if (testCase[5] == null) {
4016                    errln("Test case #" + testNum +
4017                            ": ArithmeticException must be thrown, but got formatted result: " +
4018                            s);
4019                } else {
4020                    assertEquals("Test case #" + testNum, testCase[5], s);
4021                }
4022            }
4023
4024            testNum++;
4025        }
4026    }
4027
4028    @Test
4029    public void TestSignificantDigits() {
4030        double input[] = {
4031                0, 0,
4032                123, -123,
4033                12345, -12345,
4034                123.45, -123.45,
4035                123.44501, -123.44501,
4036                0.001234, -0.001234,
4037                0.00000000123, -0.00000000123,
4038                0.0000000000000000000123, -0.0000000000000000000123,
4039                1.2, -1.2,
4040                0.0000000012344501, -0.0000000012344501,
4041                123445.01, -123445.01,
4042                12344501000000000000000000000000000.0, -12344501000000000000000000000000000.0,
4043        };
4044        String[] expected = {
4045                "0.00", "0.00",
4046                "123", "-123",
4047                "12345", "-12345",
4048                "123.45", "-123.45",
4049                "123.45", "-123.45",
4050                "0.001234", "-0.001234",
4051                "0.00000000123", "-0.00000000123",
4052                "0.0000000000000000000123", "-0.0000000000000000000123",
4053                "1.20", "-1.20",
4054                "0.0000000012345", "-0.0000000012345",
4055                "123450", "-123450",
4056                "12345000000000000000000000000000000", "-12345000000000000000000000000000000",
4057        };
4058        DecimalFormat numberFormat =
4059                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
4060        numberFormat.setSignificantDigitsUsed(true);
4061        numberFormat.setMinimumSignificantDigits(3);
4062        numberFormat.setMaximumSignificantDigits(5);
4063        numberFormat.setGroupingUsed(false);
4064        for (int i = 0; i < input.length; i++) {
4065            assertEquals("TestSignificantDigits", expected[i], numberFormat.format(input[i]));
4066        }
4067    }
4068
4069    @Test
4070    public void TestBug9936() {
4071        DecimalFormat numberFormat =
4072                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
4073        assertFalse("", numberFormat.areSignificantDigitsUsed());
4074
4075        numberFormat.setSignificantDigitsUsed(true);
4076        assertTrue("", numberFormat.areSignificantDigitsUsed());
4077
4078        numberFormat.setSignificantDigitsUsed(false);
4079        assertFalse("", numberFormat.areSignificantDigitsUsed());
4080
4081        numberFormat.setMinimumSignificantDigits(3);
4082        assertTrue("", numberFormat.areSignificantDigitsUsed());
4083
4084        numberFormat.setSignificantDigitsUsed(false);
4085        numberFormat.setMaximumSignificantDigits(6);
4086        assertTrue("", numberFormat.areSignificantDigitsUsed());
4087    }
4088
4089    @Test
4090    public void TestShowZero() {
4091        DecimalFormat numberFormat =
4092                (DecimalFormat) NumberFormat.getInstance(ULocale.US);
4093        numberFormat.setSignificantDigitsUsed(true);
4094        numberFormat.setMaximumSignificantDigits(3);
4095        assertEquals("TestShowZero", "0", numberFormat.format(0.0));
4096    }
4097
4098    @Test
4099    public void TestCurrencyPlurals() {
4100        String[][] tests = {
4101                {"en", "USD", "1", "1 US dollar"},
4102                {"en", "USD", "1.0", "1.0 US dollars"},
4103                {"en", "USD", "1.00", "1.00 US dollars"},
4104                {"en", "USD", "1.99", "1.99 US dollars"},
4105                {"en", "AUD", "1", "1 Australian dollar"},
4106                {"en", "AUD", "1.00", "1.00 Australian dollars"},
4107                {"sl", "USD", "1", "1 ameri\u0161ki dolar"},
4108                {"sl", "USD", "2", "2 ameri\u0161ka dolarja"},
4109                {"sl", "USD", "3", "3 ameri\u0161ki dolarji"},
4110                {"sl", "USD", "5", "5 ameriških dolarjev"},
4111                {"fr", "USD", "1.99", "1,99 dollar des États-Unis"},
4112                {"ru", "RUB", "1", "1 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0439 \u0440\u0443\u0431\u043B\u044C"},
4113                {"ru", "RUB", "2", "2 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0445 \u0440\u0443\u0431\u043B\u044F"},
4114                {"ru", "RUB", "5", "5 \u0440\u043E\u0441\u0441\u0438\u0439\u0441\u043A\u0438\u0445 \u0440\u0443\u0431\u043B\u0435\u0439"},
4115        };
4116        for (String test[] : tests) {
4117            DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getInstance(new ULocale(test[0]), NumberFormat.PLURALCURRENCYSTYLE);
4118            numberFormat.setCurrency(Currency.getInstance(test[1]));
4119            double number = Double.parseDouble(test[2]);
4120            int dotPos = test[2].indexOf('.');
4121            int decimals = dotPos < 0 ? 0 : test[2].length() - dotPos - 1;
4122            int digits = dotPos < 0 ? test[2].length() : test[2].length() - 1;
4123            numberFormat.setMaximumFractionDigits(decimals);
4124            numberFormat.setMinimumFractionDigits(decimals);
4125            String actual = numberFormat.format(number);
4126            assertEquals(test[0] + "\t" + test[1] + "\t" + test[2], test[3], actual);
4127            numberFormat.setMaximumSignificantDigits(digits);
4128            numberFormat.setMinimumSignificantDigits(digits);
4129            actual = numberFormat.format(number);
4130            assertEquals(test[0] + "\t" + test[1] + "\t" + test[2], test[3], actual);
4131        }
4132    }
4133
4134    @Test
4135    public void TestCustomCurrencySignAndSeparator() {
4136        DecimalFormatSymbols custom = new DecimalFormatSymbols(ULocale.US);
4137
4138        custom.setCurrencySymbol("*");
4139        custom.setMonetaryGroupingSeparator('^');
4140        custom.setMonetaryDecimalSeparator(':');
4141
4142        DecimalFormat fmt = new DecimalFormat("\u00A4 #,##0.00", custom);
4143
4144        final String numstr = "* 1^234:56";
4145        expect2(fmt, 1234.56, numstr);
4146    }
4147
4148    @Test
4149    public void TestParseSignsAndMarks() {
4150        class SignsAndMarksItem {
4151            public String locale;
4152            public boolean lenient;
4153            public String numString;
4154            public double value;
4155             // Simple constructor
4156            public SignsAndMarksItem(String loc, boolean lnt, String numStr, double val) {
4157                locale = loc;
4158                lenient = lnt;
4159                numString = numStr;
4160                value = val;
4161            }
4162        };
4163        final SignsAndMarksItem[] items = {
4164            // *** Note, ICU4J lenient number parsing does not handle arbitrary whitespace, but can
4165            // treat some whitespace as a grouping separator. The cases marked *** below depend
4166            // on isGroupingUsed() being set for the locale, which in turn depends on grouping
4167            // separators being present in the decimalFormat pattern for the locale (& num sys).
4168            //
4169            //                    locale                lenient numString                               value
4170            new SignsAndMarksItem("en",                 false,  "12",                                    12 ),
4171            new SignsAndMarksItem("en",                 true,   "12",                                    12 ),
4172            new SignsAndMarksItem("en",                 false,  "-23",                                  -23 ),
4173            new SignsAndMarksItem("en",                 true,   "-23",                                  -23 ),
4174            new SignsAndMarksItem("en",                 true,   "- 23",                                 -23 ), // ***
4175            new SignsAndMarksItem("en",                 false,  "\u200E-23",                            -23 ),
4176            new SignsAndMarksItem("en",                 true,   "\u200E-23",                            -23 ),
4177            new SignsAndMarksItem("en",                 true,   "\u200E- 23",                           -23 ), // ***
4178
4179            new SignsAndMarksItem("en@numbers=arab",    false,  "\u0663\u0664",                          34 ),
4180            new SignsAndMarksItem("en@numbers=arab",    true,   "\u0663\u0664",                          34 ),
4181            new SignsAndMarksItem("en@numbers=arab",    false,  "-\u0664\u0665",                        -45 ),
4182            new SignsAndMarksItem("en@numbers=arab",    true,   "-\u0664\u0665",                        -45 ),
4183            new SignsAndMarksItem("en@numbers=arab",    true,   "- \u0664\u0665",                       -45 ), // ***
4184            new SignsAndMarksItem("en@numbers=arab",    false,  "\u200F-\u0664\u0665",                  -45 ),
4185            new SignsAndMarksItem("en@numbers=arab",    true,   "\u200F-\u0664\u0665",                  -45 ),
4186            new SignsAndMarksItem("en@numbers=arab",    true,   "\u200F- \u0664\u0665",                 -45 ), // ***
4187
4188            new SignsAndMarksItem("en@numbers=arabext", false,  "\u06F5\u06F6",                          56 ),
4189            new SignsAndMarksItem("en@numbers=arabext", true,   "\u06F5\u06F6",                          56 ),
4190            new SignsAndMarksItem("en@numbers=arabext", false,  "-\u06F6\u06F7",                        -67 ),
4191            new SignsAndMarksItem("en@numbers=arabext", true,   "-\u06F6\u06F7",                        -67 ),
4192            new SignsAndMarksItem("en@numbers=arabext", true,   "- \u06F6\u06F7",                       -67 ), // ***
4193            new SignsAndMarksItem("en@numbers=arabext", false,  "\u200E-\u200E\u06F6\u06F7",            -67 ),
4194            new SignsAndMarksItem("en@numbers=arabext", true,   "\u200E-\u200E\u06F6\u06F7",            -67 ),
4195            new SignsAndMarksItem("en@numbers=arabext", true,   "\u200E-\u200E \u06F6\u06F7",           -67 ), // ***
4196
4197            new SignsAndMarksItem("he",                 false,  "12",                                    12 ),
4198            new SignsAndMarksItem("he",                 true,   "12",                                    12 ),
4199            new SignsAndMarksItem("he",                 false,  "-23",                                  -23 ),
4200            new SignsAndMarksItem("he",                 true,   "-23",                                  -23 ),
4201            new SignsAndMarksItem("he",                 true,   "- 23",                                 -23 ), // ***
4202            new SignsAndMarksItem("he",                 false,  "\u200E-23",                            -23 ),
4203            new SignsAndMarksItem("he",                 true,   "\u200E-23",                            -23 ),
4204            new SignsAndMarksItem("he",                 true,   "\u200E- 23",                           -23 ), // ***
4205
4206            new SignsAndMarksItem("ar",                 false,  "\u0663\u0664",                          34 ),
4207            new SignsAndMarksItem("ar",                 true,   "\u0663\u0664",                          34 ),
4208            new SignsAndMarksItem("ar",                 false,  "-\u0664\u0665",                        -45 ),
4209            new SignsAndMarksItem("ar",                 true,   "-\u0664\u0665",                        -45 ),
4210            new SignsAndMarksItem("ar",                 true,   "- \u0664\u0665",                       -45 ), // ***
4211            new SignsAndMarksItem("ar",                 false,  "\u200F-\u0664\u0665",                  -45 ),
4212            new SignsAndMarksItem("ar",                 true,   "\u200F-\u0664\u0665",                  -45 ),
4213            new SignsAndMarksItem("ar",                 true,   "\u200F- \u0664\u0665",                 -45 ), // ***
4214
4215            new SignsAndMarksItem("ar_MA",              false,  "12",                                    12 ),
4216            new SignsAndMarksItem("ar_MA",              true,   "12",                                    12 ),
4217            new SignsAndMarksItem("ar_MA",              false,  "-23",                                  -23 ),
4218            new SignsAndMarksItem("ar_MA",              true,   "-23",                                  -23 ),
4219            new SignsAndMarksItem("ar_MA",              true,   "- 23",                                 -23 ), // ***
4220            new SignsAndMarksItem("ar_MA",              false,  "\u200E-23",                            -23 ),
4221            new SignsAndMarksItem("ar_MA",              true,   "\u200E-23",                            -23 ),
4222            new SignsAndMarksItem("ar_MA",              true,   "\u200E- 23",                           -23 ), // ***
4223
4224            new SignsAndMarksItem("fa",                 false,  "\u06F5\u06F6",                          56 ),
4225            new SignsAndMarksItem("fa",                 true,   "\u06F5\u06F6",                          56 ),
4226            new SignsAndMarksItem("fa",                 false,  "\u2212\u06F6\u06F7",                   -67 ),
4227            new SignsAndMarksItem("fa",                 true,   "\u2212\u06F6\u06F7",                   -67 ),
4228            new SignsAndMarksItem("fa",                 true,   "\u2212 \u06F6\u06F7",                  -67 ), // ***
4229            new SignsAndMarksItem("fa",                 false,  "\u200E\u2212\u200E\u06F6\u06F7",       -67 ),
4230            new SignsAndMarksItem("fa",                 true,   "\u200E\u2212\u200E\u06F6\u06F7",       -67 ),
4231            new SignsAndMarksItem("fa",                 true,   "\u200E\u2212\u200E \u06F6\u06F7",      -67 ), // ***
4232
4233            new SignsAndMarksItem("ps",                 false,  "\u06F5\u06F6",                          56 ),
4234            new SignsAndMarksItem("ps",                 true,   "\u06F5\u06F6",                          56 ),
4235            new SignsAndMarksItem("ps",                 false,  "-\u06F6\u06F7",                        -67 ),
4236            new SignsAndMarksItem("ps",                 true,   "-\u06F6\u06F7",                        -67 ),
4237            new SignsAndMarksItem("ps",                 true,   "- \u06F6\u06F7",                       -67 ), // ***
4238            new SignsAndMarksItem("ps",                 false,  "\u200E-\u200E\u06F6\u06F7",            -67 ),
4239            new SignsAndMarksItem("ps",                 true,   "\u200E-\u200E\u06F6\u06F7",            -67 ),
4240            new SignsAndMarksItem("ps",                 true,   "\u200E-\u200E \u06F6\u06F7",           -67 ), // ***
4241            new SignsAndMarksItem("ps",                 false,  "-\u200E\u06F6\u06F7",                  -67 ),
4242            new SignsAndMarksItem("ps",                 true,   "-\u200E\u06F6\u06F7",                  -67 ),
4243            new SignsAndMarksItem("ps",                 true,   "-\u200E \u06F6\u06F7",                 -67 ), // ***
4244        };
4245        for (SignsAndMarksItem item: items) {
4246            ULocale locale = new ULocale(item.locale);
4247            NumberFormat numfmt = NumberFormat.getInstance(locale);
4248            if (numfmt != null) {
4249                numfmt.setParseStrict(!item.lenient);
4250                ParsePosition ppos = new ParsePosition(0);
4251                Number num = numfmt.parse(item.numString, ppos);
4252                if (num != null && ppos.getIndex() == item.numString.length()) {
4253                    double parsedValue = num.doubleValue();
4254                    if (parsedValue != item.value) {
4255                        errln("FAIL: locale " + item.locale + ", lenient " + item.lenient + ", parse of \"" + item.numString + "\" gives value " + parsedValue);
4256                    }
4257                } else {
4258                    errln("FAIL: locale " + item.locale + ", lenient " + item.lenient + ", parse of \"" + item.numString + "\" gives position " + ppos.getIndex());
4259                }
4260            } else {
4261                errln("FAIL: NumberFormat.getInstance for locale " + item.locale);
4262            }
4263        }
4264    }
4265
4266    @Test
4267    public void TestContext() {
4268        // just a minimal sanity check for now
4269        NumberFormat nfmt = NumberFormat.getInstance();
4270        DisplayContext context = nfmt.getContext(DisplayContext.Type.CAPITALIZATION);
4271        if (context != DisplayContext.CAPITALIZATION_NONE) {
4272            errln("FAIL: Initial NumberFormat.getContext() is not CAPITALIZATION_NONE");
4273        }
4274        nfmt.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
4275        context = nfmt.getContext(DisplayContext.Type.CAPITALIZATION);
4276        if (context != DisplayContext.CAPITALIZATION_FOR_STANDALONE) {
4277            errln("FAIL: NumberFormat.getContext() does not return the value set, CAPITALIZATION_FOR_STANDALONE");
4278        }
4279    }
4280
4281    @Test
4282    public void TestAccountingCurrency() {
4283        String[][] tests = {
4284                //locale              num         curr fmt per loc     curr std fmt         curr acct fmt        rt
4285                {"en_US",             "1234.5",   "$1,234.50",         "$1,234.50",         "$1,234.50",         "true"},
4286                {"en_US@cf=account",  "1234.5",   "$1,234.50",         "$1,234.50",         "$1,234.50",         "true"},
4287                {"en_US",             "-1234.5",  "-$1,234.50",        "-$1,234.50",        "($1,234.50)",       "true"},
4288                {"en_US@cf=standard", "-1234.5",  "-$1,234.50",        "-$1,234.50",        "($1,234.50)",       "true"},
4289                {"en_US@cf=account",  "-1234.5",  "($1,234.50)",       "-$1,234.50",        "($1,234.50)",       "true"},
4290                {"en_US",             "0",        "$0.00",             "$0.00",             "$0.00",             "true"},
4291                {"en_US",             "-0.2",     "-$0.20",            "-$0.20",            "($0.20)",           "true"},
4292                {"en_US@cf=standard", "-0.2",     "-$0.20",            "-$0.20",            "($0.20)",           "true"},
4293                {"en_US@cf=account",  "-0.2",     "($0.20)",           "-$0.20",            "($0.20)",           "true"},
4294                {"ja_JP",             "10000",    "¥10,000",          "¥10,000",          "¥10,000",          "true" },
4295                {"ja_JP",             "-1000.5",  "-¥1,000",          "-¥1,000",          "(¥1,000)",         "false"},
4296                {"ja_JP@cf=account",  "-1000.5",  "(¥1,000)",         "-¥1,000",          "(¥1,000)",         "false"},
4297                {"de_DE",             "-23456.7", "-23.456,70\u00A0€", "-23.456,70\u00A0€", "-23.456,70\u00A0€", "true" },
4298        };
4299        for (String[] data : tests) {
4300            ULocale loc = new ULocale(data[0]);
4301            double num = Double.parseDouble(data[1]);
4302            String fmtPerLocExpected   = data[2];
4303            String fmtStandardExpected = data[3];
4304            String fmtAccountExpected  = data[4];
4305            boolean rt = Boolean.parseBoolean(data[5]);
4306
4307            NumberFormat fmtPerLoc = NumberFormat.getInstance(loc, NumberFormat.CURRENCYSTYLE);
4308            expect(fmtPerLoc, num, fmtPerLocExpected, rt);
4309
4310            NumberFormat fmtStandard = NumberFormat.getInstance(loc, NumberFormat.STANDARDCURRENCYSTYLE);
4311            expect(fmtStandard, num, fmtStandardExpected, rt);
4312
4313            NumberFormat fmtAccount = NumberFormat.getInstance(loc, NumberFormat.ACCOUNTINGCURRENCYSTYLE);
4314            expect(fmtAccount, num, fmtAccountExpected, rt);
4315        }
4316    }
4317
4318    @Test
4319    public void TestCurrencyUsage() {
4320        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
4321        // compare the Currency and Currency Cash Digits
4322        // Note that as of CLDR 26:
4323        // * TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
4324        // * CAD rounds to .05 in the cash style only.
4325        for (int i = 0; i < 2; i++) {
4326            String original_expected = "PKR124";
4327            DecimalFormat custom = null;
4328            if (i == 0) {
4329                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=PKR"),
4330                        DecimalFormat.CURRENCYSTYLE);
4331
4332                String original = custom.format(123.567);
4333                assertEquals("Test Currency Context", original_expected, original);
4334
4335                // test the getter
4336                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(),
4337                        Currency.CurrencyUsage.STANDARD);
4338                custom.setCurrencyUsage(Currency.CurrencyUsage.CASH);
4339                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
4340            } else {
4341                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=PKR"),
4342                        DecimalFormat.CASHCURRENCYSTYLE);
4343
4344                // test the getter
4345                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
4346            }
4347
4348            String cash_currency = custom.format(123.567);
4349            String cash_currency_expected = "PKR124";
4350            assertEquals("Test Currency Context", cash_currency_expected, cash_currency);
4351        }
4352
4353        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
4354        // compare the Currency and Currency Cash Rounding
4355        for (int i = 0; i < 2; i++) {
4356            String original_rounding_expected = "CA$123.57";
4357            DecimalFormat fmt = null;
4358            if (i == 0) {
4359                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
4360                        DecimalFormat.CURRENCYSTYLE);
4361
4362                String original_rounding = fmt.format(123.566);
4363                assertEquals("Test Currency Context", original_rounding_expected, original_rounding);
4364
4365                fmt.setCurrencyUsage(Currency.CurrencyUsage.CASH);
4366            } else {
4367                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
4368                        DecimalFormat.CASHCURRENCYSTYLE);
4369            }
4370
4371            String cash_rounding_currency = fmt.format(123.567);
4372            String cash__rounding_currency_expected = "CA$123.55";
4373            assertEquals("Test Currency Context", cash__rounding_currency_expected, cash_rounding_currency);
4374        }
4375
4376        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
4377        // Test the currency change
4378        for (int i = 0; i < 2; i++) {
4379            DecimalFormat fmt2 = null;
4380            if (i == 1) {
4381                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
4382                        NumberFormat.CURRENCYSTYLE);
4383                fmt2.setCurrencyUsage(Currency.CurrencyUsage.CASH);
4384            } else {
4385                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
4386                        NumberFormat.CASHCURRENCYSTYLE);
4387            }
4388
4389            fmt2.setCurrency(Currency.getInstance("PKR"));
4390            String PKR_changed = fmt2.format(123.567);
4391            String PKR_changed_expected = "PKR124";
4392            assertEquals("Test Currency Context", PKR_changed_expected, PKR_changed);
4393        }
4394    }
4395
4396    @Test
4397    public void TestParseRequiredDecimalPoint() {
4398
4399        String[] testPattern = { "00.####", "00.0", "00" };
4400
4401        String value2Parse = "99";
4402        double parseValue  =  99;
4403        DecimalFormat parser = new DecimalFormat();
4404        double result;
4405        boolean hasDecimalPoint;
4406        for (int i = 0; i < testPattern.length; i++) {
4407            parser.applyPattern(testPattern[i]);
4408            hasDecimalPoint = testPattern[i].contains(".");
4409
4410            parser.setDecimalPatternMatchRequired(false);
4411            try {
4412                result = parser.parse(value2Parse).doubleValue();
4413                assertEquals("wrong parsed value", parseValue, result);
4414            } catch (ParseException e) {
4415                TestFmwk.errln("Parsing " + value2Parse + " should have succeeded with " + testPattern[i] +
4416                            " and isDecimalPointMatchRequired set to: " + parser.isDecimalPatternMatchRequired());
4417            }
4418
4419            parser.setDecimalPatternMatchRequired(true);
4420            try {
4421                result = parser.parse(value2Parse).doubleValue();
4422                if(hasDecimalPoint){
4423                    TestFmwk.errln("Parsing " + value2Parse + " should NOT have succeeded with " + testPattern[i] +
4424                            " and isDecimalPointMatchRequired set to: " + parser.isDecimalPatternMatchRequired());
4425                }
4426            } catch (ParseException e) {
4427                    // OK, should fail
4428            }
4429        }
4430
4431    }
4432
4433
4434    //TODO(junit): investigate
4435    @Test
4436    public void TestDataDrivenICU() {
4437        DataDrivenNumberFormatTestUtility.runSuite(
4438                "numberformattestspecification.txt", ICU);
4439    }
4440
4441    //TODO(junit): investigate
4442    @Test
4443    public void TestDataDrivenJDK() {
4444        // Android patch: Android java.text.DecimalFormat is actually ICU.
4445        if (TestUtil.getJavaVendor() == TestUtil.JavaVendor.Android) return;
4446        // Android patch end.
4447        DataDrivenNumberFormatTestUtility.runSuite(
4448                "numberformattestspecification.txt", JDK);
4449    }
4450
4451
4452    @Test
4453    public void TestCurrFmtNegSameAsPositive() {
4454        DecimalFormatSymbols decfmtsym = DecimalFormatSymbols.getInstance(Locale.US);
4455        decfmtsym.setMinusSign('\u200B'); // ZERO WIDTH SPACE, in ICU4J cannot set to empty string
4456        DecimalFormat decfmt = new DecimalFormat("\u00A4#,##0.00;\u00A4#,##0.00", decfmtsym);
4457        String currFmtResult = decfmt.format(-100.0);
4458        if (!currFmtResult.equals("\u200B$100.00")) {
4459            errln("decfmt.toPattern results wrong, expected \u200B$100.00, got " + currFmtResult);
4460        }
4461    }
4462
4463    @Test
4464    public void TestNumberFormatTestDataToString() {
4465        new NumberFormatTestData().toString();
4466    }
4467
4468   // Testing for Issue 11805.
4469    @Test
4470    public void TestFormatToCharacterIteratorIssue11805 () {
4471        final double number = -350.76;
4472        DecimalFormat dfUS = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.US);
4473        String strUS = dfUS.format(number);
4474        Set<AttributedCharacterIterator.Attribute> resultUS  = dfUS.formatToCharacterIterator(number).getAllAttributeKeys();
4475        assertEquals("Negative US Results: " + strUS, 5, resultUS.size());
4476
4477        // For each test, add assert that all the fields are present and in the right spot.
4478        // TODO: Add tests for identify and position of each field, as in IntlTestDecimalFormatAPIC.
4479
4480        DecimalFormat dfDE = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.GERMANY);
4481        String strDE = dfDE.format(number);
4482        Set<AttributedCharacterIterator.Attribute> resultDE  = dfDE.formatToCharacterIterator(number).getAllAttributeKeys();
4483        assertEquals("Negative DE Results: " + strDE, 5, resultDE.size());
4484
4485        DecimalFormat dfIN = (DecimalFormat) DecimalFormat.getCurrencyInstance(new Locale("hi", "in"));
4486        String strIN = dfIN.format(number);
4487        Set<AttributedCharacterIterator.Attribute> resultIN  = dfIN.formatToCharacterIterator(number).getAllAttributeKeys();
4488        assertEquals("Negative IN Results: " + strIN, 5, resultIN.size());
4489
4490        DecimalFormat dfJP = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.JAPAN);
4491        String strJP = dfJP.format(number);
4492        Set<AttributedCharacterIterator.Attribute> resultJP  = dfJP.formatToCharacterIterator(number).getAllAttributeKeys();
4493        assertEquals("Negative JA Results: " + strJP, 3, resultJP.size());
4494
4495        DecimalFormat dfGB = (DecimalFormat) DecimalFormat.getCurrencyInstance(new Locale("en", "gb"));
4496        String strGB = dfGB.format(number);
4497        Set<AttributedCharacterIterator.Attribute> resultGB  = dfGB.formatToCharacterIterator(number).getAllAttributeKeys();
4498        assertEquals("Negative GB Results: " + strGB , 5, resultGB.size());
4499
4500        DecimalFormat dfPlural = (DecimalFormat) NumberFormat.getInstance(new Locale("en", "gb"),
4501            NumberFormat.PLURALCURRENCYSTYLE);
4502        strGB = dfPlural.format(number);
4503        resultGB = dfPlural.formatToCharacterIterator(number).getAllAttributeKeys();
4504        assertEquals("Negative GB Results: " + strGB , 5, resultGB.size());
4505
4506        strGB = dfPlural.format(1);
4507        resultGB = dfPlural.formatToCharacterIterator(1).getAllAttributeKeys();
4508        assertEquals("Negative GB Results: " + strGB , 4, resultGB.size());
4509
4510        // Test output with unit value.
4511        DecimalFormat auPlural = (DecimalFormat) NumberFormat.getInstance(new Locale("en", "au"),
4512                NumberFormat.PLURALCURRENCYSTYLE);
4513        String strAU = auPlural.format(1L);
4514        Set<AttributedCharacterIterator.Attribute> resultAU  =
4515                auPlural.formatToCharacterIterator(1L).getAllAttributeKeys();
4516        assertEquals("Unit AU Result: " + strAU , 4, resultAU.size());
4517
4518        // Verify Permille fields.
4519        DecimalFormatSymbols sym = new DecimalFormatSymbols(new Locale("en", "gb"));
4520        DecimalFormat dfPermille = new DecimalFormat("####0.##\u2030", sym);
4521        strGB = dfPermille.format(number);
4522        resultGB = dfPermille.formatToCharacterIterator(number).getAllAttributeKeys();
4523        assertEquals("Negative GB Permille Results: " + strGB , 3, resultGB.size());
4524    }
4525
4526    // Testing for Issue 11808.
4527    @Test
4528    public void TestRoundUnnecessarytIssue11808 () {
4529        DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance();
4530        StringBuffer result = new StringBuffer("");
4531        df.setRoundingMode(BigDecimal.ROUND_UNNECESSARY);
4532        df.applyPattern("00.0#E0");
4533
4534        try {
4535            df.format(99999.0, result, new FieldPosition(0));
4536            fail("Missing ArithmeticException for double: " + result);
4537        } catch (ArithmeticException expected) {
4538            // The exception should be thrown, since rounding is needed.
4539        }
4540
4541        try {
4542            result = df.format(99999, result, new FieldPosition(0));
4543            fail("Missing ArithmeticException for int: " + result);
4544       } catch (ArithmeticException expected) {
4545           // The exception should be thrown, since rounding is needed.
4546        }
4547
4548        try {
4549            result = df.format(new BigInteger("999999"), result, new FieldPosition(0));
4550            fail("Missing ArithmeticException for BigInteger: " + result);
4551        } catch (ArithmeticException expected) {
4552            // The exception should be thrown, since rounding is needed.
4553        }
4554
4555        try {
4556            result = df.format(new BigDecimal("99999"), result, new FieldPosition(0));
4557            fail("Missing ArithmeticException for BigDecimal: " + result);
4558        } catch (ArithmeticException expected) {
4559            // The exception should be thrown, since rounding is needed.
4560        }
4561
4562        try {
4563            result = df.format(new BigDecimal("-99999"), result, new FieldPosition(0));
4564            fail("Missing ArithmeticException for BigDecimal: " + result);
4565        } catch (ArithmeticException expected) {
4566            // The exception should be thrown, since rounding is needed.
4567        }
4568    }
4569
4570    // Testing for Issue 11735.
4571    @Test
4572    public void TestNPEIssue11735() {
4573        DecimalFormat fmt = new DecimalFormat("0", new DecimalFormatSymbols(new ULocale("en")));
4574        ParsePosition ppos = new ParsePosition(0);
4575        assertEquals("Currency symbol missing in parse. Expect null result.",
4576                fmt.parseCurrency("53.45", ppos), null);
4577    }
4578
4579    private void CompareAttributedCharacterFormatOutput(AttributedCharacterIterator iterator,
4580        List<FieldContainer> expected, String formattedOutput) {
4581
4582        List<FieldContainer> result = new ArrayList<FieldContainer>();
4583        while (iterator.getIndex() != iterator.getEndIndex()) {
4584            int start = iterator.getRunStart();
4585            int end = iterator.getRunLimit();
4586            Iterator it = iterator.getAttributes().keySet().iterator();
4587            AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it.next();
4588            Object value = iterator.getAttribute(attribute);
4589            result.add(new FieldContainer(start, end, attribute, value));
4590            iterator.setIndex(end);
4591        }
4592        assertEquals("Comparing vector length for " + formattedOutput,
4593            expected.size(), result.size());
4594
4595        if (!expected.containsAll(result)) {
4596          // Print information on the differences.
4597          for (int i = 0; i < expected.size(); i++) {
4598            System.out.println("     expected[" + i + "] =" +
4599                expected.get(i).start + " " +
4600                expected.get(i).end + " " +
4601                expected.get(i).attribute + " " +
4602                expected.get(i).value);
4603            System.out.println(" result[" + i + "] =" +
4604                result.get(i).start + " " +
4605                result.get(i).end + " " +
4606                result.get(i).attribute + " " +
4607                result.get(i).value);
4608          }
4609        }
4610        // TODO: restore when #11914 is fixed.
4611        // assertTrue("Comparing vector results for " + formattedOutput,
4612        //    expected.containsAll(result));
4613    }
4614
4615    // Testing for Issue 11914, missing FieldPositions for some field types.
4616    @Test
4617    public void TestNPEIssue11914() {
4618        // First test: Double value with grouping separators.
4619        List<FieldContainer> v1 = new ArrayList<FieldContainer>(7);
4620        v1.add(new FieldContainer(0, 3, NumberFormat.Field.INTEGER));
4621        v1.add(new FieldContainer(3, 4, NumberFormat.Field.GROUPING_SEPARATOR));
4622        v1.add(new FieldContainer(4, 7, NumberFormat.Field.INTEGER));
4623        v1.add(new FieldContainer(7, 8, NumberFormat.Field.GROUPING_SEPARATOR));
4624        v1.add(new FieldContainer(8, 11, NumberFormat.Field.INTEGER));
4625        v1.add(new FieldContainer(11, 12, NumberFormat.Field.DECIMAL_SEPARATOR));
4626        v1.add(new FieldContainer(12, 15, NumberFormat.Field.FRACTION));
4627
4628        Number number = new Double(123456789.9753);
4629        ULocale usLoc = new ULocale("en-US");
4630        DecimalFormatSymbols US = new DecimalFormatSymbols(usLoc);
4631
4632        NumberFormat outFmt = NumberFormat.getNumberInstance(usLoc);
4633        String numFmtted = outFmt.format(number);
4634        AttributedCharacterIterator iterator =
4635                outFmt.formatToCharacterIterator(number);
4636        CompareAttributedCharacterFormatOutput(iterator, v1, numFmtted);
4637
4638        // Second test: Double with scientific notation formatting.
4639        List<FieldContainer> v2 = new ArrayList<FieldContainer>(7);
4640        v2.add(new FieldContainer(0, 1, NumberFormat.Field.INTEGER));
4641        v2.add(new FieldContainer(1, 2, NumberFormat.Field.DECIMAL_SEPARATOR));
4642        v2.add(new FieldContainer(2, 5, NumberFormat.Field.FRACTION));
4643        v2.add(new FieldContainer(5, 6, NumberFormat.Field.EXPONENT_SYMBOL));
4644        v2.add(new FieldContainer(6, 7, NumberFormat.Field.EXPONENT_SIGN));
4645        v2.add(new FieldContainer(7, 8, NumberFormat.Field.EXPONENT));
4646        DecimalFormat fmt2 = new DecimalFormat("0.###E+0", US);
4647
4648        numFmtted = fmt2.format(number);
4649        iterator = fmt2.formatToCharacterIterator(number);
4650        CompareAttributedCharacterFormatOutput(iterator, v2, numFmtted);
4651
4652        // Third test. BigInteger with grouping separators.
4653        List<FieldContainer> v3 = new ArrayList<FieldContainer>(7);
4654        v3.add(new FieldContainer(0, 1, NumberFormat.Field.SIGN));
4655        v3.add(new FieldContainer(1, 2, NumberFormat.Field.INTEGER));
4656        v3.add(new FieldContainer(2, 3, NumberFormat.Field.GROUPING_SEPARATOR));
4657        v3.add(new FieldContainer(3, 6, NumberFormat.Field.INTEGER));
4658        v3.add(new FieldContainer(6, 7, NumberFormat.Field.GROUPING_SEPARATOR));
4659        v3.add(new FieldContainer(7, 10, NumberFormat.Field.INTEGER));
4660        v3.add(new FieldContainer(10, 11, NumberFormat.Field.GROUPING_SEPARATOR));
4661        v3.add(new FieldContainer(11, 14, NumberFormat.Field.INTEGER));
4662        v3.add(new FieldContainer(14, 15, NumberFormat.Field.GROUPING_SEPARATOR));
4663        v3.add(new FieldContainer(15, 18, NumberFormat.Field.INTEGER));
4664        v3.add(new FieldContainer(18, 19, NumberFormat.Field.GROUPING_SEPARATOR));
4665        v3.add(new FieldContainer(19, 22, NumberFormat.Field.INTEGER));
4666        v3.add(new FieldContainer(22, 23, NumberFormat.Field.GROUPING_SEPARATOR));
4667        v3.add(new FieldContainer(23, 26, NumberFormat.Field.INTEGER));
4668        BigInteger bigNumberInt = new BigInteger("-1234567890246813579");
4669        String fmtNumberBigInt = outFmt.format(bigNumberInt);
4670
4671        iterator = outFmt.formatToCharacterIterator(bigNumberInt);
4672        CompareAttributedCharacterFormatOutput(iterator, v3, fmtNumberBigInt);
4673
4674        // Fourth test: BigDecimal with exponential formatting.
4675        List<FieldContainer> v4 = new ArrayList<FieldContainer>(7);
4676        v4.add(new FieldContainer(0, 1, NumberFormat.Field.SIGN));
4677        v4.add(new FieldContainer(1, 2, NumberFormat.Field.INTEGER));
4678        v4.add(new FieldContainer(2, 3, NumberFormat.Field.DECIMAL_SEPARATOR));
4679        v4.add(new FieldContainer(3, 6, NumberFormat.Field.FRACTION));
4680        v4.add(new FieldContainer(6, 7, NumberFormat.Field.EXPONENT_SYMBOL));
4681        v4.add(new FieldContainer(7, 8, NumberFormat.Field.EXPONENT_SIGN));
4682        v4.add(new FieldContainer(8, 9, NumberFormat.Field.EXPONENT));
4683
4684        java.math.BigDecimal numberBigD = new java.math.BigDecimal(-123456789);
4685        String fmtNumberBigDExp = fmt2.format(numberBigD);
4686
4687        iterator = fmt2.formatToCharacterIterator(numberBigD);
4688        CompareAttributedCharacterFormatOutput(iterator, v4, fmtNumberBigDExp);
4689
4690    }
4691
4692    // Test that the decimal is shown even when there are no fractional digits
4693    @Test
4694    public void Test11621() throws Exception {
4695        String pat = "0.##E0";
4696
4697        DecimalFormatSymbols icuSym = new DecimalFormatSymbols(Locale.US);
4698        DecimalFormat icuFmt = new DecimalFormat(pat, icuSym);
4699        icuFmt.setDecimalSeparatorAlwaysShown(true);
4700        String icu = ((NumberFormat)icuFmt).format(299792458);
4701
4702        java.text.DecimalFormatSymbols jdkSym = new java.text.DecimalFormatSymbols(Locale.US);
4703        java.text.DecimalFormat jdkFmt = new java.text.DecimalFormat(pat,jdkSym);
4704        jdkFmt.setDecimalSeparatorAlwaysShown(true);
4705        String jdk = ((java.text.NumberFormat)jdkFmt).format(299792458);
4706
4707        assertEquals("ICU and JDK placement of decimal in exponent", jdk, icu);
4708    }
4709
4710    private void checkFormatWithField(String testInfo, Format format, Object object,
4711            String expected, Format.Field field, int begin, int end) {
4712        StringBuffer buffer = new StringBuffer();
4713        FieldPosition pos = new FieldPosition(field);
4714        format.format(object, buffer, pos);
4715
4716        assertEquals("Test " + testInfo + ": incorrect formatted text", expected, buffer.toString());
4717
4718        if (begin != pos.getBeginIndex() || end != pos.getEndIndex()) {
4719            assertEquals("Index mismatch", field + " " + begin + ".." + end,
4720                pos.getFieldAttribute() + " " + pos.getBeginIndex() + ".." + pos.getEndIndex());
4721        }
4722    }
4723
4724    @Test
4725    public void TestMissingFieldPositionsCurrency() {
4726        DecimalFormat formatter = (DecimalFormat) NumberFormat.getCurrencyInstance(ULocale.US);
4727        Number number = new Double(92314587.66);
4728        String result = "$92,314,587.66";
4729
4730        checkFormatWithField("currency", formatter, number, result,
4731            NumberFormat.Field.CURRENCY, 0, 1);
4732        checkFormatWithField("integer", formatter, number, result,
4733            NumberFormat.Field.INTEGER, 1, 11);
4734        checkFormatWithField("grouping separator", formatter, number, result,
4735            NumberFormat.Field.GROUPING_SEPARATOR, 3, 4);
4736        checkFormatWithField("decimal separator", formatter, number, result,
4737            NumberFormat.Field.DECIMAL_SEPARATOR, 11, 12);
4738        checkFormatWithField("fraction", formatter, number, result,
4739            NumberFormat.Field.FRACTION, 12, 14);
4740    }
4741
4742    @Test
4743    public void TestMissingFieldPositionsNegativeDouble() {
4744        // test for exponential fields with double
4745        DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4746        Number number = new Double(-12345678.90123);
4747        DecimalFormat formatter = new DecimalFormat("0.#####E+00", us_symbols);
4748        String numFmtted = formatter.format(number);
4749
4750        checkFormatWithField("sign", formatter, number, numFmtted,
4751            NumberFormat.Field.SIGN, 0, 1);
4752        checkFormatWithField("integer", formatter, number, numFmtted,
4753            NumberFormat.Field.INTEGER, 1, 2);
4754        checkFormatWithField("decimal separator", formatter, number, numFmtted,
4755            NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3);
4756        checkFormatWithField("exponent symbol", formatter, number, numFmtted,
4757            NumberFormat.Field.EXPONENT_SYMBOL, 8, 9);
4758        checkFormatWithField("exponent sign", formatter, number, numFmtted,
4759            NumberFormat.Field.EXPONENT_SIGN, 9, 10);
4760        checkFormatWithField("exponent", formatter, number, numFmtted,
4761            NumberFormat.Field.EXPONENT, 10, 12);
4762    }
4763
4764    @Test
4765    public void TestMissingFieldPositionsPerCent() {
4766        // Check PERCENT
4767        DecimalFormat percentFormat = (DecimalFormat) NumberFormat.getPercentInstance(ULocale.US);
4768        Number number = new Double(-0.986);
4769        String numberFormatted = percentFormat.format(number);
4770        checkFormatWithField("sign", percentFormat, number, numberFormatted,
4771            NumberFormat.Field.SIGN, 0, 1);
4772        checkFormatWithField("integer", percentFormat, number, numberFormatted,
4773            NumberFormat.Field.INTEGER, 1, 3);
4774        checkFormatWithField("percent", percentFormat, number, numberFormatted,
4775            NumberFormat.Field.PERCENT, 3, 4);
4776    }
4777
4778    @Test
4779    public void TestMissingFieldPositionsPerCentPattern() {
4780        // Check PERCENT with more digits
4781        DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4782        DecimalFormat fmtPercent = new DecimalFormat("0.#####%", us_symbols);
4783        Number number = new Double(-0.986);
4784        String numFmtted = fmtPercent.format(number);
4785
4786        checkFormatWithField("sign", fmtPercent, number, numFmtted,
4787            NumberFormat.Field.SIGN, 0, 1);
4788        checkFormatWithField("integer", fmtPercent, number, numFmtted,
4789            NumberFormat.Field.INTEGER, 1, 3);
4790        checkFormatWithField("decimal separator", fmtPercent, number, numFmtted,
4791            NumberFormat.Field.DECIMAL_SEPARATOR, 3, 4);
4792        checkFormatWithField("fraction", fmtPercent, number, numFmtted,
4793            NumberFormat.Field.FRACTION, 4, 5);
4794        checkFormatWithField("percent", fmtPercent, number, numFmtted,
4795            NumberFormat.Field.PERCENT, 5, 6);
4796    }
4797
4798    @Test
4799    public void TestMissingFieldPositionsPerMille() {
4800        // Check PERMILLE
4801        DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4802        DecimalFormat fmtPerMille = new DecimalFormat("0.######‰", us_symbols);
4803        Number numberPermille = new Double(-0.98654);
4804        String numFmtted = fmtPerMille.format(numberPermille);
4805
4806        checkFormatWithField("sign", fmtPerMille, numberPermille, numFmtted,
4807            NumberFormat.Field.SIGN, 0, 1);
4808        checkFormatWithField("integer", fmtPerMille, numberPermille, numFmtted,
4809            NumberFormat.Field.INTEGER, 1, 4);
4810        checkFormatWithField("decimal separator", fmtPerMille, numberPermille, numFmtted,
4811            NumberFormat.Field.DECIMAL_SEPARATOR, 4, 5);
4812        checkFormatWithField("fraction", fmtPerMille, numberPermille, numFmtted,
4813            NumberFormat.Field.FRACTION, 5, 7);
4814        checkFormatWithField("permille", fmtPerMille, numberPermille, numFmtted,
4815            NumberFormat.Field.PERMILLE, 7, 8);
4816    }
4817
4818    @Test
4819    public void TestMissingFieldPositionsNegativeBigInt() {
4820      DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4821        DecimalFormat formatter = new DecimalFormat("0.#####E+0", us_symbols);
4822        Number number = new BigDecimal("-123456789987654321");
4823        String bigDecFmtted = formatter.format(number);
4824
4825        checkFormatWithField("sign", formatter, number, bigDecFmtted,
4826            NumberFormat.Field.SIGN, 0, 1);
4827        checkFormatWithField("integer", formatter, number, bigDecFmtted,
4828            NumberFormat.Field.INTEGER, 1, 2);
4829        checkFormatWithField("decimal separator", formatter, number, bigDecFmtted,
4830            NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3);
4831        checkFormatWithField("exponent symbol", formatter, number, bigDecFmtted,
4832            NumberFormat.Field.EXPONENT_SYMBOL, 8, 9);
4833        checkFormatWithField("exponent sign", formatter, number, bigDecFmtted,
4834            NumberFormat.Field.EXPONENT_SIGN, 9, 10);
4835        checkFormatWithField("exponent", formatter, number, bigDecFmtted,
4836            NumberFormat.Field.EXPONENT, 10, 12);
4837    }
4838
4839    @Test
4840    public void TestMissingFieldPositionsNegativeLong() {
4841        Number number = new Long("-123456789987654321");
4842        DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4843        DecimalFormat formatter = new DecimalFormat("0.#####E+0", us_symbols);
4844        String longFmtted = formatter.format(number);
4845
4846        checkFormatWithField("sign", formatter, number, longFmtted,
4847            NumberFormat.Field.SIGN, 0, 1);
4848        checkFormatWithField("integer", formatter, number, longFmtted,
4849            NumberFormat.Field.INTEGER, 1, 2);
4850        checkFormatWithField("decimal separator", formatter, number, longFmtted,
4851            NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3);
4852        checkFormatWithField("exponent symbol", formatter, number, longFmtted,
4853            NumberFormat.Field.EXPONENT_SYMBOL, 8, 9);
4854        checkFormatWithField("exponent sign", formatter, number, longFmtted,
4855            NumberFormat.Field.EXPONENT_SIGN, 9, 10);
4856        checkFormatWithField("exponent", formatter, number, longFmtted,
4857            NumberFormat.Field.EXPONENT, 10, 12);
4858    }
4859
4860    @Test
4861    public void TestMissingFieldPositionsPositiveBigDec() {
4862        // Check complex positive;negative pattern.
4863        DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4864        DecimalFormat fmtPosNegSign = new DecimalFormat("+0.####E+00;-0.#######E+0", us_symbols);
4865        Number positiveExp = new Double("9876543210");
4866        String posExpFormatted = fmtPosNegSign.format(positiveExp);
4867
4868        checkFormatWithField("sign", fmtPosNegSign, positiveExp, posExpFormatted,
4869            NumberFormat.Field.SIGN, 0, 1);
4870        checkFormatWithField("integer", fmtPosNegSign, positiveExp, posExpFormatted,
4871            NumberFormat.Field.INTEGER, 1, 2);
4872        checkFormatWithField("decimal separator", fmtPosNegSign, positiveExp, posExpFormatted,
4873            NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3);
4874        checkFormatWithField("fraction", fmtPosNegSign, positiveExp, posExpFormatted,
4875            NumberFormat.Field.FRACTION, 3, 7);
4876        checkFormatWithField("exponent symbol", fmtPosNegSign, positiveExp, posExpFormatted,
4877            NumberFormat.Field.EXPONENT_SYMBOL, 7, 8);
4878        checkFormatWithField("exponent sign", fmtPosNegSign, positiveExp, posExpFormatted,
4879            NumberFormat.Field.EXPONENT_SIGN, 8, 9);
4880        checkFormatWithField("exponent", fmtPosNegSign, positiveExp, posExpFormatted,
4881            NumberFormat.Field.EXPONENT, 9, 11);
4882    }
4883
4884    @Test
4885    public void TestMissingFieldPositionsNegativeBigDec() {
4886        // Check complex positive;negative pattern.
4887      DecimalFormatSymbols us_symbols = new DecimalFormatSymbols(ULocale.US);
4888        DecimalFormat fmtPosNegSign = new DecimalFormat("+0.####E+00;-0.#######E+0", us_symbols);
4889        Number negativeExp = new BigDecimal("-0.000000987654321083");
4890        String negExpFormatted = fmtPosNegSign.format(negativeExp);
4891
4892        checkFormatWithField("sign", fmtPosNegSign, negativeExp, negExpFormatted,
4893            NumberFormat.Field.SIGN, 0, 1);
4894        checkFormatWithField("integer", fmtPosNegSign, negativeExp, negExpFormatted,
4895            NumberFormat.Field.INTEGER, 1, 2);
4896        checkFormatWithField("decimal separator", fmtPosNegSign, negativeExp, negExpFormatted,
4897            NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3);
4898        checkFormatWithField("fraction", fmtPosNegSign, negativeExp, negExpFormatted,
4899            NumberFormat.Field.FRACTION, 3, 7);
4900        checkFormatWithField("exponent symbol", fmtPosNegSign, negativeExp, negExpFormatted,
4901            NumberFormat.Field.EXPONENT_SYMBOL, 7, 8);
4902        checkFormatWithField("exponent sign", fmtPosNegSign, negativeExp, negExpFormatted,
4903            NumberFormat.Field.EXPONENT_SIGN, 8, 9);
4904        checkFormatWithField("exponent", fmtPosNegSign, negativeExp, negExpFormatted,
4905            NumberFormat.Field.EXPONENT, 9, 11);
4906    }
4907
4908    @Test
4909    public void TestStringSymbols() {
4910        DecimalFormatSymbols symbols = new DecimalFormatSymbols(ULocale.US);
4911
4912        String[] customDigits = {"(0)", "(1)", "(2)", "(3)", "(4)", "(5)", "(6)", "(7)", "(8)", "(9)"};
4913        symbols.setDigitStrings(customDigits);
4914        symbols.setDecimalSeparatorString("~~");
4915        symbols.setGroupingSeparatorString("^^");
4916
4917        DecimalFormat fmt = new DecimalFormat("#,##0.0#", symbols);
4918
4919        expect2(fmt, 1234567.89, "(1)^^(2)(3)(4)^^(5)(6)(7)~~(8)(9)");
4920    }
4921}
4922