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) 1996-2015, International Business Machines Corporation and    *
7 * others. All Rights Reserved.                                                *
8 *******************************************************************************
9 */
10package android.icu.dev.test.format;
11
12import java.math.BigInteger;
13import java.text.ParseException;
14import java.util.Locale;
15import java.util.Random;
16
17import org.junit.Test;
18import org.junit.runner.RunWith;
19import org.junit.runners.JUnit4;
20
21import android.icu.dev.test.TestFmwk;
22import android.icu.math.BigDecimal;
23import android.icu.text.DecimalFormat;
24import android.icu.text.DecimalFormatSymbols;
25import android.icu.text.DisplayContext;
26import android.icu.text.NumberFormat;
27import android.icu.text.RuleBasedNumberFormat;
28import android.icu.util.ULocale;
29import android.icu.testsharding.MainTestShard;
30
31/**
32 * This does not test lenient parse mode, since testing the default implementation
33 * introduces a dependency on collation.  See RbnfLenientScannerTest.
34 */
35@MainTestShard
36@RunWith(JUnit4.class)
37public class RbnfTest extends TestFmwk {
38    static String fracRules =
39        "%main:\n" +
40        // this rule formats the number if it's 1 or more.  It formats
41        // the integral part using a DecimalFormat ("#,##0" puts
42        // thousands separators in the right places) and the fractional
43        // part using %%frac.  If there is no fractional part, it
44        // just shows the integral part.
45        "    x.0: <#,##0<[ >%%frac>];\n" +
46        // this rule formats the number if it's between 0 and 1.  It
47        // shows only the fractional part (0.5 shows up as "1/2," not
48        // "0 1/2")
49        "    0.x: >%%frac>;\n" +
50        // the fraction rule set.  This works the same way as the one in the
51        // preceding example: We multiply the fractional part of the number
52        // being formatted by each rule's base value and use the rule that
53        // produces the result closest to 0 (or the first rule that produces 0).
54        // Since we only provide rules for the numbers from 2 to 10, we know
55        // we'll get a fraction with a denominator between 2 and 10.
56        // "<0<" causes the numerator of the fraction to be formatted
57        // using numerals
58        "%%frac:\n" +
59        "    2: 1/2;\n" +
60        "    3: <0</3;\n" +
61        "    4: <0</4;\n" +
62        "    5: <0</5;\n" +
63        "    6: <0</6;\n" +
64        "    7: <0</7;\n" +
65        "    8: <0</8;\n" +
66        "    9: <0</9;\n" +
67        "   10: <0</10;\n";
68
69    @Test
70    public void TestCoverage() {
71        String durationInSecondsRules =
72                // main rule set for formatting with words
73                "%with-words:\n"
74                        // take care of singular and plural forms of "second"
75                        + "    0 seconds; 1 second; =0= seconds;\n"
76                        // use %%min to format values greater than 60 seconds
77                        + "    60/60: <%%min<[, >>];\n"
78                        // use %%hr to format values greater than 3,600 seconds
79                        // (the ">>>" below causes us to see the number of minutes
80                        // when when there are zero minutes)
81                        + "    3600/60: <%%hr<[, >>>];\n"
82                        // this rule set takes care of the singular and plural forms
83                        // of "minute"
84                        + "%%min:\n"
85                        + "    0 minutes; 1 minute; =0= minutes;\n"
86                        // this rule set takes care of the singular and plural forms
87                        // of "hour"
88                        + "%%hr:\n"
89                        + "    0 hours; 1 hour; =0= hours;\n"
90
91                        // main rule set for formatting in numerals
92                        + "%in-numerals:\n"
93                        // values below 60 seconds are shown with "sec."
94                        + "    =0= sec.;\n"
95                        // higher values are shown with colons: %%min-sec is used for
96                        // values below 3,600 seconds...
97                        + "    60: =%%min-sec=;\n"
98                        // ...and %%hr-min-sec is used for values of 3,600 seconds
99                        // and above
100                        + "    3600: =%%hr-min-sec=;\n"
101                        // this rule causes values of less than 10 minutes to show without
102                        // a leading zero
103                        + "%%min-sec:\n"
104                        + "    0: :=00=;\n"
105                        + "    60/60: <0<>>;\n"
106                        // this rule set is used for values of 3,600 or more.  Minutes are always
107                        // shown, and always shown with two digits
108                        + "%%hr-min-sec:\n"
109                        + "    0: :=00=;\n"
110                        + "    60/60: <00<>>;\n"
111                        + "    3600/60: <#,##0<:>>>;\n"
112                        // the lenient-parse rules allow several different characters to be used
113                        // as delimiters between hours, minutes, and seconds
114                        + "%%lenient-parse:\n"
115                        + "    & : = . = ' ' = -;\n";
116
117        // extra calls to boost coverage numbers
118        RuleBasedNumberFormat fmt0 = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
119        RuleBasedNumberFormat fmt1 = (RuleBasedNumberFormat)fmt0.clone();
120        RuleBasedNumberFormat fmt2 = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
121        if (!fmt0.equals(fmt0)) {
122            errln("self equality fails");
123        }
124        if (!fmt0.equals(fmt1)) {
125            errln("clone equality fails");
126        }
127        if (!fmt0.equals(fmt2)) {
128            errln("duplicate equality fails");
129        }
130        String str = fmt0.toString();
131        logln(str);
132
133        RuleBasedNumberFormat fmt3 =  new RuleBasedNumberFormat(durationInSecondsRules);
134
135        if (fmt0.equals(fmt3)) {
136            errln("nonequal fails");
137        }
138        if (!fmt3.equals(fmt3)) {
139            errln("self equal 2 fails");
140        }
141        str = fmt3.toString();
142        logln(str);
143
144        String[] names = fmt3.getRuleSetNames();
145
146        try {
147            fmt3.setDefaultRuleSet(null);
148            fmt3.setDefaultRuleSet("%%foo");
149            errln("sdrf %%foo didn't fail");
150        }
151        catch (Exception e) {
152            logln("Got the expected exception");
153        }
154
155        try {
156            fmt3.setDefaultRuleSet("%bogus");
157            errln("sdrf %bogus didn't fail");
158        }
159        catch (Exception e) {
160            logln("Got the expected exception");
161        }
162
163        try {
164            str = fmt3.format(2.3, names[0]);
165            logln(str);
166            str = fmt3.format(2.3, "%%foo");
167            errln("format double %%foo didn't fail");
168        }
169        catch (Exception e) {
170            logln("Got the expected exception");
171        }
172
173        try {
174            str = fmt3.format(123L, names[0]);
175            logln(str);
176            str = fmt3.format(123L, "%%foo");
177            errln("format double %%foo didn't fail");
178        }
179        catch (Exception e) {
180            logln("Got the expected exception");
181        }
182
183        RuleBasedNumberFormat fmt4 = new RuleBasedNumberFormat(fracRules, Locale.ENGLISH);
184        RuleBasedNumberFormat fmt5 = new RuleBasedNumberFormat(fracRules, Locale.ENGLISH);
185        str = fmt4.toString();
186        logln(str);
187        if (!fmt4.equals(fmt5)) {
188            errln("duplicate 2 equality failed");
189        }
190        str = fmt4.format(123L);
191        logln(str);
192        try {
193            Number num = fmt4.parse(str);
194            logln(num.toString());
195        }
196        catch (Exception e) {
197            errln("parse caught exception");
198        }
199
200        str = fmt4.format(.000123);
201        logln(str);
202        try {
203            Number num = fmt4.parse(str);
204            logln(num.toString());
205        }
206        catch (Exception e) {
207            errln("parse caught exception");
208        }
209
210        str = fmt4.format(456.000123);
211        logln(str);
212        try {
213            Number num = fmt4.parse(str);
214            logln(num.toString());
215        }
216        catch (Exception e) {
217            errln("parse caught exception");
218        }
219    }
220
221    @Test
222    public void TestUndefinedSpellout() {
223        Locale greek = new Locale("el", "", "");
224        RuleBasedNumberFormat[] formatters = {
225                new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.SPELLOUT),
226                new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.ORDINAL),
227                new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.DURATION),
228        };
229
230        String[] data = {
231                "0",
232                "1",
233                "15",
234                "20",
235                "23",
236                "73",
237                "88",
238                "100",
239                "106",
240                "127",
241                "200",
242                "579",
243                "1,000",
244                "2,000",
245                "3,004",
246                "4,567",
247                "15,943",
248                "105,000",
249                "2,345,678",
250                "-36",
251                "-36.91215",
252                "234.56789"
253        };
254
255        NumberFormat decFormat = NumberFormat.getInstance(Locale.US);
256        for (int j = 0; j < formatters.length; ++j) {
257            android.icu.text.NumberFormat formatter = formatters[j];
258            logln("formatter[" + j + "]");
259            for (int i = 0; i < data.length; ++i) {
260                try {
261                    String result = formatter.format(decFormat.parse(data[i]));
262                    logln("[" + i + "] " + data[i] + " ==> " + result);
263                }
264                catch (Exception e) {
265                    errln("formatter[" + j + "], data[" + i + "] " + data[i] + " threw exception " + e.getMessage());
266                }
267            }
268        }
269    }
270
271    /**
272     * Perform a simple spot check on the English spellout rules
273     */
274    @Test
275    public void TestEnglishSpellout() {
276        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US,
277                RuleBasedNumberFormat.SPELLOUT);
278        String[][] testData = {
279                { "1", "one" },
280                { "15", "fifteen" },
281                { "20", "twenty" },
282                { "23", "twenty-three" },
283                { "73", "seventy-three" },
284                { "88", "eighty-eight" },
285                { "100", "one hundred" },
286                { "106", "one hundred six" },
287                { "127", "one hundred twenty-seven" },
288                { "200", "two hundred" },
289                { "579", "five hundred seventy-nine" },
290                { "1,000", "one thousand" },
291                { "2,000", "two thousand" },
292                { "3,004", "three thousand four" },
293                { "4,567", "four thousand five hundred sixty-seven" },
294                { "15,943", "fifteen thousand nine hundred forty-three" },
295                { "2,345,678", "two million three hundred forty-five "
296                        + "thousand six hundred seventy-eight" },
297                { "-36", "minus thirty-six" },
298                { "234.567", "two hundred thirty-four point five six seven" }
299        };
300
301        doTest(formatter, testData, true);
302    }
303
304    /**
305     * Perform a simple spot check on the English ordinal-abbreviation rules
306     */
307    @Test
308    public void TestOrdinalAbbreviations() {
309        RuleBasedNumberFormat formatter= new RuleBasedNumberFormat(Locale.US,
310                RuleBasedNumberFormat.ORDINAL);
311        String[][] testData = {
312                { "1", "1st" },
313                { "2", "2nd" },
314                { "3", "3rd" },
315                { "4", "4th" },
316                { "7", "7th" },
317                { "10", "10th" },
318                { "11", "11th" },
319                { "13", "13th" },
320                { "20", "20th" },
321                { "21", "21st" },
322                { "22", "22nd" },
323                { "23", "23rd" },
324                { "24", "24th" },
325                { "33", "33rd" },
326                { "102", "102nd" },
327                { "312", "312th" },
328                { "12,345", "12,345th" }
329        };
330
331        doTest(formatter, testData, false);
332    }
333
334    /**
335     * Perform a simple spot check on the duration-formatting rules
336     */
337    @Test
338    public void TestDurations() {
339        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US,
340                RuleBasedNumberFormat.DURATION);
341        String[][] testData = {
342                { "3,600", "1:00:00" },             //move me and I fail
343                { "0", "0 sec." },
344                { "1", "1 sec." },
345                { "24", "24 sec." },
346                { "60", "1:00" },
347                { "73", "1:13" },
348                { "145", "2:25" },
349                { "666", "11:06" },
350                //            { "3,600", "1:00:00" },
351                { "3,740", "1:02:20" },
352                { "10,293", "2:51:33" }
353        };
354
355        doTest(formatter, testData, true);
356    }
357
358    /**
359     * Perform a simple spot check on the Spanish spellout rules
360     */
361    @Test
362    public void TestSpanishSpellout() {
363        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("es", "es",
364                ""), RuleBasedNumberFormat.SPELLOUT);
365        String[][] testData = {
366                { "1", "uno" },
367                { "6", "seis" },
368                { "16", "diecis\u00e9is" },
369                { "20", "veinte" },
370                { "24", "veinticuatro" },
371                { "26", "veintis\u00e9is" },
372                { "73", "setenta y tres" },
373                { "88", "ochenta y ocho" },
374                { "100", "cien" },
375                { "106", "ciento seis" },
376                { "127", "ciento veintisiete" },
377                { "200", "doscientos" },
378                { "579", "quinientos setenta y nueve" },
379                { "1,000", "mil" },
380                { "2,000", "dos mil" },
381                { "3,004", "tres mil cuatro" },
382                { "4,567", "cuatro mil quinientos sesenta y siete" },
383                { "15,943", "quince mil novecientos cuarenta y tres" },
384                { "2,345,678", "dos millones trescientos cuarenta y cinco mil "
385                        + "seiscientos setenta y ocho"},
386                { "-36", "menos treinta y seis" },
387                { "234.567", "doscientos treinta y cuatro coma cinco seis siete" }
388        };
389
390        doTest(formatter, testData, true);
391    }
392
393    /**
394     * Perform a simple spot check on the French spellout rules
395     */
396    @Test
397    public void TestFrenchSpellout() {
398        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.FRANCE,
399                RuleBasedNumberFormat.SPELLOUT);
400        String[][] testData = {
401                { "1", "un" },
402                { "15", "quinze" },
403                { "20", "vingt" },
404                { "21", "vingt-et-un" },
405                { "23", "vingt-trois" },
406                { "62", "soixante-deux" },
407                { "70", "soixante-dix" },
408                { "71", "soixante-et-onze" },
409                { "73", "soixante-treize" },
410                { "80", "quatre-vingts" },
411                { "88", "quatre-vingt-huit" },
412                { "100", "cent" },
413                { "106", "cent six" },
414                { "127", "cent vingt-sept" },
415                { "200", "deux cents" },
416                { "579", "cinq cent soixante-dix-neuf" },
417                { "1,000", "mille" },
418                { "1,123", "mille cent vingt-trois" },
419                { "1,594", "mille cinq cent quatre-vingt-quatorze" },
420                { "2,000", "deux mille" },
421                { "3,004", "trois mille quatre" },
422                { "4,567", "quatre mille cinq cent soixante-sept" },
423                { "15,943", "quinze mille neuf cent quarante-trois" },
424                { "2,345,678", "deux millions trois cent quarante-cinq mille "
425                        + "six cent soixante-dix-huit" },
426                { "-36", "moins trente-six" },
427                { "234.567", "deux cent trente-quatre virgule cinq six sept" }
428        };
429
430        doTest(formatter, testData, true);
431    }
432
433    /**
434     * Perform a simple spot check on the Swiss French spellout rules
435     */
436    @Test
437    public void TestSwissFrenchSpellout() {
438        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("fr", "CH"),
439                RuleBasedNumberFormat.SPELLOUT);
440        String[][] testData = {
441                { "1", "un" },
442                { "15", "quinze" },
443                { "20", "vingt" },
444                { "21", "vingt-et-un" },
445                { "23", "vingt-trois" },
446                { "62", "soixante-deux" },
447                { "70", "septante" },
448                { "71", "septante-et-un" },
449                { "73", "septante-trois" },
450                { "80", "huitante" },
451                { "88", "huitante-huit" },
452                { "100", "cent" },
453                { "106", "cent six" },
454                { "127", "cent vingt-sept" },
455                { "200", "deux cents" },
456                { "579", "cinq cent septante-neuf" },
457                { "1,000", "mille" },
458                { "1,123", "mille cent vingt-trois" },
459                { "1,594", "mille cinq cent nonante-quatre" },
460                { "2,000", "deux mille" },
461                { "3,004", "trois mille quatre" },
462                { "4,567", "quatre mille cinq cent soixante-sept" },
463                { "15,943", "quinze mille neuf cent quarante-trois" },
464                { "2,345,678", "deux millions trois cent quarante-cinq mille "
465                        + "six cent septante-huit" },
466                { "-36", "moins trente-six" },
467                { "234.567", "deux cent trente-quatre virgule cinq six sept" }
468        };
469
470        doTest(formatter, testData, true);
471    }
472
473    /**
474     * Perform a simple spot check on the Italian spellout rules
475     */
476    @Test
477    public void TestItalianSpellout() {
478        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.ITALIAN,
479                RuleBasedNumberFormat.SPELLOUT);
480        String[][] testData = {
481                { "1", "uno" },
482                { "15", "quindici" },
483                { "20", "venti" },
484                { "23", "venti\u00ADtr\u00E9" },
485                { "73", "settanta\u00ADtr\u00E9" },
486                { "88", "ottant\u00ADotto" },
487                { "100", "cento" },
488                { "106", "cento\u00ADsei" },
489                { "108", "cent\u00ADotto" },
490                { "127", "cento\u00ADventi\u00ADsette" },
491                { "181", "cent\u00ADottant\u00ADuno" },
492                { "200", "due\u00ADcento" },
493                { "579", "cinque\u00ADcento\u00ADsettanta\u00ADnove" },
494                { "1,000", "mille" },
495                { "2,000", "due\u00ADmila" },
496                { "3,004", "tre\u00ADmila\u00ADquattro" },
497                { "4,567", "quattro\u00ADmila\u00ADcinque\u00ADcento\u00ADsessanta\u00ADsette" },
498                { "15,943", "quindici\u00ADmila\u00ADnove\u00ADcento\u00ADquaranta\u00ADtr\u00E9" },
499                { "-36", "meno trenta\u00ADsei" },
500                { "234.567", "due\u00ADcento\u00ADtrenta\u00ADquattro virgola cinque sei sette" }
501        };
502
503        doTest(formatter, testData, true);
504    }
505
506    /**
507     * Perform a simple spot check on the German spellout rules
508     */
509    @Test
510    public void TestGermanSpellout() {
511        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.GERMANY,
512                RuleBasedNumberFormat.SPELLOUT);
513        String[][] testData = {
514                { "1", "eins" },
515                { "15", "f\u00fcnfzehn" },
516                { "20", "zwanzig" },
517                { "23", "drei\u00ADund\u00ADzwanzig" },
518                { "73", "drei\u00ADund\u00ADsiebzig" },
519                { "88", "acht\u00ADund\u00ADachtzig" },
520                { "100", "ein\u00ADhundert" },
521                { "106", "ein\u00ADhundert\u00ADsechs" },
522                { "127", "ein\u00ADhundert\u00ADsieben\u00ADund\u00ADzwanzig" },
523                { "200", "zwei\u00ADhundert" },
524                { "579", "f\u00fcnf\u00ADhundert\u00ADneun\u00ADund\u00ADsiebzig" },
525                { "1,000", "ein\u00ADtausend" },
526                { "2,000", "zwei\u00ADtausend" },
527                { "3,004", "drei\u00ADtausend\u00ADvier" },
528                { "4,567", "vier\u00ADtausend\u00ADf\u00fcnf\u00ADhundert\u00ADsieben\u00ADund\u00ADsechzig" },
529                { "15,943", "f\u00fcnfzehn\u00ADtausend\u00ADneun\u00ADhundert\u00ADdrei\u00ADund\u00ADvierzig" },
530                { "2,345,678", "zwei Millionen drei\u00ADhundert\u00ADf\u00fcnf\u00ADund\u00ADvierzig\u00ADtausend\u00AD"
531                        + "sechs\u00ADhundert\u00ADacht\u00ADund\u00ADsiebzig" }
532        };
533
534        doTest(formatter, testData, true);
535    }
536
537    /**
538     * Perform a simple spot check on the Thai spellout rules
539     */
540    @Test
541    public void TestThaiSpellout() {
542        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("th", "TH"),
543                RuleBasedNumberFormat.SPELLOUT);
544        String[][] testData = {
545                { "0", "\u0e28\u0e39\u0e19\u0e22\u0e4c" },
546                { "1", "\u0e2b\u0e19\u0e36\u0e48\u0e07" },
547                { "10", "\u0e2a\u0e34\u0e1a" },
548                { "11", "\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14" },
549                { "21", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14" },
550                { "101", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e23\u0e49\u0e2d\u0e22\u200b\u0e2b\u0e19\u0e36\u0e48\u0e07" },
551                { "1.234", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e2d\u0e07\u0e2a\u0e32\u0e21\u0e2a\u0e35\u0e48" },
552                { "21.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" },
553                { "22.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e2d\u0e07\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" },
554                { "23.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e32\u0e21\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" },
555                { "123.45", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e23\u0e49\u0e2d\u0e22\u200b\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e32\u0e21\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" },
556                { "12,345.678", "\u0E2B\u0E19\u0E36\u0E48\u0E07\u200b\u0E2B\u0E21\u0E37\u0E48\u0E19\u200b\u0E2A\u0E2D\u0E07\u200b\u0E1E\u0E31\u0E19\u200b\u0E2A\u0E32\u0E21\u200b\u0E23\u0E49\u0E2D\u0E22\u200b\u0E2A\u0E35\u0E48\u200b\u0E2A\u0E34\u0E1A\u200b\u0E2B\u0E49\u0E32\u200b\u0E08\u0E38\u0E14\u200b\u0E2B\u0E01\u0E40\u0E08\u0E47\u0E14\u0E41\u0E1B\u0E14" },
557        };
558
559        doTest(formatter, testData, true);
560    }
561
562    /**
563     * Perform a simple spot check on the ordinal spellout rules
564     */
565    @Test
566    public void TestPluralRules() {
567        String enRules = "%digits-ordinal:"
568                + "-x: −>>;"
569                + "0: =#,##0=$(ordinal,one{st}two{nd}few{rd}other{th})$;";
570        RuleBasedNumberFormat enFormatter = new RuleBasedNumberFormat(enRules, ULocale.ENGLISH);
571        String[][] enTestData = {
572                { "1", "1st" },
573                { "2", "2nd" },
574                { "3", "3rd" },
575                { "4", "4th" },
576                { "11", "11th" },
577                { "12", "12th" },
578                { "13", "13th" },
579                { "14", "14th" },
580                { "21", "21st" },
581                { "22", "22nd" },
582                { "23", "23rd" },
583                { "24", "24th" },
584        };
585
586        doTest(enFormatter, enTestData, true);
587
588        // This is trying to model the feminine form, but don't worry about the details too much.
589        // We're trying to test the plural rules.
590        String ruRules = "%spellout-numbering:"
591                + "-x: минус >>;"
592                + "x.x: [<< $(cardinal,one{целый}other{целых})$ ]>%%fractions-feminine>;"
593                + "0: ноль;"
594                + "1: один;"
595                + "2: два;"
596                + "3: три;"
597                + "4: четыре;"
598                + "5: пять;"
599                + "6: шесть;"
600                + "7: семь;"
601                + "8: восемь;"
602                + "9: девять;"
603                + "10: десять;"
604                + "11: одиннадцать;"
605                + "12: двенадцать;"
606                + "13: тринадцать;"
607                + "14: четырнадцать;"
608                + "15: пятнадцать;"
609                + "16: шестнадцать;"
610                + "17: семнадцать;"
611                + "18: восемнадцать;"
612                + "19: девятнадцать;"
613                + "20: двадцать[ >>];"
614                + "30: тридцать[ >>];"
615                + "40: сорок[ >>];"
616                + "50: пятьдесят[ >>];"
617                + "60: шестьдесят[ >>];"
618                + "70: семьдесят[ >>];"
619                + "80: восемьдесят[ >>];"
620                + "90: девяносто[ >>];"
621                + "100: сто[ >>];"
622                + "200: <<сти[ >>];"
623                + "300: <<ста[ >>];"
624                + "500: <<сот[ >>];"
625                + "1000: << $(cardinal,one{тысяча}few{тысячи}other{тысяч})$[ >>];"
626                + "1000000: << $(cardinal,one{миллион}few{миллионы}other{миллионов})$[ >>];"
627                + "%%fractions-feminine:"
628                + "10: <%spellout-numbering< $(cardinal,one{десятая}other{десятых})$;"
629                + "100: <%spellout-numbering< $(cardinal,one{сотая}other{сотых})$;";
630        RuleBasedNumberFormat ruFormatter = new RuleBasedNumberFormat(ruRules, new ULocale("ru"));
631        String[][] ruTestData = {
632                { "1", "один" },
633                { "100", "сто" },
634                { "125", "сто двадцать пять" },
635                { "399", "триста девяносто девять" },
636                { "1,000", "один тысяча" },
637                { "1,001", "один тысяча один" },
638                { "2,000", "два тысячи" },
639                { "2,001", "два тысячи один" },
640                { "2,002", "два тысячи два" },
641                { "3,333", "три тысячи триста тридцать три" },
642                { "5,000", "пять тысяч" },
643                { "11,000", "одиннадцать тысяч" },
644                { "21,000", "двадцать один тысяча" },
645                { "22,000", "двадцать два тысячи" },
646                { "25,001", "двадцать пять тысяч один" },
647                { "0.1", "один десятая" },
648                { "0.2", "два десятых" },
649                { "0.21", "двадцать один сотая" },
650                { "0.22", "двадцать два сотых" },
651                { "21.1", "двадцать один целый один десятая" },
652                { "22.2", "двадцать два целых два десятых" },
653        };
654
655        doTest(ruFormatter, ruTestData, true);
656
657        // Make sure there are no divide by 0 errors.
658        String result = new RuleBasedNumberFormat(ruRules, new ULocale("ru")).format(21000);
659        if (!"двадцать один тысяча".equals(result)) {
660            errln("Got " + result + " for 21000");
661        }
662    }
663
664    /**
665     * Perform a simple spot check on the parsing going into an infinite loop for alternate rules.
666     */
667    @Test
668    public void TestMultiplePluralRules() {
669        // This is trying to model the feminine form, but don't worry about the details too much.
670        // We're trying to test the plural rules where there are different prefixes.
671        String ruRules = "%spellout-cardinal-feminine-genitive:"
672                + "-x: минус >>;"
673                + "x.x: << запятая >>;"
674                + "0: ноля;"
675                + "1: одной;"
676                + "2: двух;"
677                + "3: трех;"
678                + "4: четырех;"
679                + "5: пяти;"
680                + "6: шести;"
681                + "7: семи;"
682                + "8: восьми;"
683                + "9: девяти;"
684                + "10: десяти;"
685                + "11: одиннадцати;"
686                + "12: двенадцати;"
687                + "13: тринадцати;"
688                + "14: четырнадцати;"
689                + "15: пятнадцати;"
690                + "16: шестнадцати;"
691                + "17: семнадцати;"
692                + "18: восемнадцати;"
693                + "19: девятнадцати;"
694                + "20: двадцати[ >>];"
695                + "30: тридцати[ >>];"
696                + "40: сорока[ >>];"
697                + "50: пятидесяти[ >>];"
698                + "60: шестидесяти[ >>];"
699                + "70: семидесяти[ >>];"
700                + "80: восемидесяти[ >>];"
701                + "90: девяноста[ >>];"
702                + "100: ста[ >>];"
703                + "200: <<сот[ >>];"
704                + "1000: << $(cardinal,one{тысяча}few{тысячи}other{тысяч})$[ >>];"
705                + "1000000: =#,##0=;"
706                + "%spellout-cardinal-feminine:"
707                + "-x: минус >>;"
708                + "x.x: << запятая >>;"
709                + "0: ноль;"
710                + "1: одна;"
711                + "2: две;"
712                + "3: три;"
713                + "4: четыре;"
714                + "5: пять;"
715                + "6: шесть;"
716                + "7: семь;"
717                + "8: восемь;"
718                + "9: девять;"
719                + "10: десять;"
720                + "11: одиннадцать;"
721                + "12: двенадцать;"
722                + "13: тринадцать;"
723                + "14: четырнадцать;"
724                + "15: пятнадцать;"
725                + "16: шестнадцать;"
726                + "17: семнадцать;"
727                + "18: восемнадцать;"
728                + "19: девятнадцать;"
729                + "20: двадцать[ >>];"
730                + "30: тридцать[ >>];"
731                + "40: сорок[ >>];"
732                + "50: пятьдесят[ >>];"
733                + "60: шестьдесят[ >>];"
734                + "70: семьдесят[ >>];"
735                + "80: восемьдесят[ >>];"
736                + "90: девяносто[ >>];"
737                + "100: сто[ >>];"
738                + "200: <<сти[ >>];"
739                + "300: <<ста[ >>];"
740                + "500: <<сот[ >>];"
741                + "1000: << $(cardinal,one{тысяча}few{тысячи}other{тысяч})$[ >>];"
742                + "1000000: =#,##0=;";
743        RuleBasedNumberFormat ruFormatter = new RuleBasedNumberFormat(ruRules, new ULocale("ru"));
744        try {
745            Number result;
746            if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000))).doubleValue()) {
747                errln("RuleBasedNumberFormat did not return the correct value. Got: " + result);
748            }
749            if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000, "%spellout-cardinal-feminine-genitive"))).doubleValue()) {
750                errln("RuleBasedNumberFormat did not return the correct value. Got: " + result);
751            }
752            if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000, "%spellout-cardinal-feminine"))).doubleValue()) {
753                errln("RuleBasedNumberFormat did not return the correct value. Got: " + result);
754            }
755        }
756        catch (ParseException e) {
757            errln(e.toString());
758        }
759    }
760
761    @Test
762    public void TestFractionalRuleSet() {
763        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(fracRules,
764                Locale.ENGLISH);
765
766        String[][] testData = {
767                { "0", "0" },
768                { "1", "1" },
769                { "10", "10" },
770                { ".1", "1/10" },
771                { ".11", "1/9" },
772                { ".125", "1/8" },
773                { ".1428", "1/7" },
774                { ".1667", "1/6" },
775                { ".2", "1/5" },
776                { ".25", "1/4" },
777                { ".333", "1/3" },
778                { ".5", "1/2" },
779                { "1.1", "1 1/10" },
780                { "2.11", "2 1/9" },
781                { "3.125", "3 1/8" },
782                { "4.1428", "4 1/7" },
783                { "5.1667", "5 1/6" },
784                { "6.2", "6 1/5" },
785                { "7.25", "7 1/4" },
786                { "8.333", "8 1/3" },
787                { "9.5", "9 1/2" },
788                { ".2222", "2/9" },
789                { ".4444", "4/9" },
790                { ".5555", "5/9" },
791                { "1.2856", "1 2/7" }
792        };
793        doTest(formatter, testData, false); // exact values aren't parsable from fractions
794    }
795
796    @Test
797    public void TestSwedishSpellout()
798    {
799        Locale locale = new Locale("sv", "", "");
800        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(locale,
801                RuleBasedNumberFormat.SPELLOUT);
802
803        String[][] testDataDefault = {
804                { "101", "ett\u00ADhundra\u00ADett" },
805                { "123", "ett\u00ADhundra\u00ADtjugo\u00ADtre" },
806                { "1,001", "et\u00ADtusen ett" },
807                { "1,100", "et\u00ADtusen ett\u00ADhundra" },
808                { "1,101", "et\u00ADtusen ett\u00ADhundra\u00ADett" },
809                { "1,234", "et\u00ADtusen tv\u00e5\u00ADhundra\u00ADtrettio\u00ADfyra" },
810                { "10,001", "tio\u00ADtusen ett" },
811                { "11,000", "elva\u00ADtusen" },
812                { "12,000", "tolv\u00ADtusen" },
813                { "20,000", "tjugo\u00ADtusen" },
814                { "21,000", "tjugo\u00ADet\u00ADtusen" },
815                { "21,001", "tjugo\u00ADet\u00ADtusen ett" },
816                { "200,000", "tv\u00e5\u00ADhundra\u00ADtusen" },
817                { "201,000", "tv\u00e5\u00ADhundra\u00ADet\u00ADtusen" },
818                { "200,200", "tv\u00e5\u00ADhundra\u00ADtusen tv\u00e5\u00ADhundra" },
819                { "2,002,000", "tv\u00e5 miljoner tv\u00e5\u00ADtusen" },
820                { "12,345,678", "tolv miljoner tre\u00ADhundra\u00ADfyrtio\u00ADfem\u00ADtusen sex\u00ADhundra\u00ADsjuttio\u00AD\u00e5tta" },
821                { "123,456.789", "ett\u00ADhundra\u00ADtjugo\u00ADtre\u00ADtusen fyra\u00ADhundra\u00ADfemtio\u00ADsex komma sju \u00e5tta nio" },
822                { "-12,345.678", "minus tolv\u00ADtusen tre\u00ADhundra\u00ADfyrtio\u00ADfem komma sex sju \u00e5tta" },
823        };
824
825        logln("testing default rules");
826        doTest(formatter, testDataDefault, true);
827
828        String[][] testDataNeutrum = {
829                { "101", "ett\u00adhundra\u00adett" },
830                { "1,001", "et\u00adtusen ett" },
831                { "1,101", "et\u00adtusen ett\u00adhundra\u00adett" },
832                { "10,001", "tio\u00adtusen ett" },
833                { "21,001", "tjugo\u00adet\u00adtusen ett" }
834        };
835
836        formatter.setDefaultRuleSet("%spellout-cardinal-neuter");
837        logln("testing neutrum rules");
838        doTest(formatter, testDataNeutrum, true);
839
840        String[][] testDataYear = {
841                { "101", "ett\u00adhundra\u00adett" },
842                { "900", "nio\u00adhundra" },
843                { "1,001", "et\u00adtusen ett" },
844                { "1,100", "elva\u00adhundra" },
845                { "1,101", "elva\u00adhundra\u00adett" },
846                { "1,234", "tolv\u00adhundra\u00adtrettio\u00adfyra" },
847                { "2,001", "tjugo\u00adhundra\u00adett" },
848                { "10,001", "tio\u00adtusen ett" }
849        };
850
851        formatter.setDefaultRuleSet("%spellout-numbering-year");
852        logln("testing year rules");
853        doTest(formatter, testDataYear, true);
854    }
855
856    @Test
857    public void TestBigNumbers() {
858        BigInteger bigI = new BigInteger("1234567890", 10);
859        StringBuffer buf = new StringBuffer();
860        RuleBasedNumberFormat fmt = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
861        fmt.format(bigI, buf, null);
862        logln("big int: " + buf.toString());
863
864        buf.setLength(0);
865        java.math.BigDecimal bigD = new java.math.BigDecimal(bigI);
866        fmt.format(bigD, buf, null);
867        logln("big dec: " + buf.toString());
868    }
869
870    @Test
871    public void TestTrailingSemicolon() {
872        String thaiRules =
873            "%default:\n" +
874            "  -x: \u0e25\u0e1a>>;\n" +
875            "  x.x: <<\u0e08\u0e38\u0e14>>>;\n" +
876            "  \u0e28\u0e39\u0e19\u0e22\u0e4c; \u0e2b\u0e19\u0e36\u0e48\u0e07; \u0e2a\u0e2d\u0e07; \u0e2a\u0e32\u0e21;\n" +
877            "  \u0e2a\u0e35\u0e48; \u0e2b\u0e49\u0e32; \u0e2b\u0e01; \u0e40\u0e08\u0e47\u0e14; \u0e41\u0e1b\u0e14;\n" +
878            "  \u0e40\u0e01\u0e49\u0e32; \u0e2a\u0e34\u0e1a; \u0e2a\u0e34\u0e1a\u0e40\u0e2d\u0e47\u0e14;\n" +
879            "  \u0e2a\u0e34\u0e1a\u0e2a\u0e2d\u0e07; \u0e2a\u0e34\u0e1a\u0e2a\u0e32\u0e21;\n" +
880            "  \u0e2a\u0e34\u0e1a\u0e2a\u0e35\u0e48; \u0e2a\u0e34\u0e1a\u0e2b\u0e49\u0e32;\n" +
881            "  \u0e2a\u0e34\u0e1a\u0e2b\u0e01; \u0e2a\u0e34\u0e1a\u0e40\u0e08\u0e47\u0e14;\n" +
882            "  \u0e2a\u0e34\u0e1a\u0e41\u0e1b\u0e14; \u0e2a\u0e34\u0e1a\u0e40\u0e01\u0e49\u0e32;\n" +
883            "  20: \u0e22\u0e35\u0e48\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
884            "  30: \u0e2a\u0e32\u0e21\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
885            "  40: \u0e2a\u0e35\u0e48\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
886            "  50: \u0e2b\u0e49\u0e32\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
887            "  60: \u0e2b\u0e01\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
888            "  70: \u0e40\u0e08\u0e47\u0e14\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
889            "  80: \u0e41\u0e1b\u0e14\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
890            "  90: \u0e40\u0e01\u0e49\u0e32\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" +
891            "  100: <<\u0e23\u0e49\u0e2d\u0e22[>>];\n" +
892            "  1000: <<\u0e1e\u0e31\u0e19[>>];\n" +
893            "  10000: <<\u0e2b\u0e21\u0e37\u0e48\u0e19[>>];\n" +
894            "  100000: <<\u0e41\u0e2a\u0e19[>>];\n" +
895            "  1,000,000: <<\u0e25\u0e49\u0e32\u0e19[>>];\n" +
896            "  1,000,000,000: <<\u0e1e\u0e31\u0e19\u0e25\u0e49\u0e32\u0e19[>>];\n" +
897            "  1,000,000,000,000: <<\u0e25\u0e49\u0e32\u0e19\u0e25\u0e49\u0e32\u0e19[>>];\n" +
898            "  1,000,000,000,000,000: =#,##0=;\n" +
899            "%%alt-ones:\n" +
900            "  \u0e28\u0e39\u0e19\u0e22\u0e4c;\n" +
901            "  \u0e40\u0e2d\u0e47\u0e14;\n" +
902            "  =%default=;\n ; ;; ";
903
904        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(thaiRules, new Locale("th", "TH", ""));
905
906        String[][] testData = {
907                { "0", "\u0e28\u0e39\u0e19\u0e22\u0e4c" },
908                { "1", "\u0e2b\u0e19\u0e36\u0e48\u0e07" },
909                { "123.45", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u0e23\u0e49\u0e2d\u0e22\u0e22\u0e35\u0e48\u0e2a\u0e34\u0e1a\u0e2a\u0e32\u0e21\u0e08\u0e38\u0e14\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" }
910        };
911
912        doTest(formatter, testData, true);
913    }
914
915    @Test
916    public void TestSmallValues() {
917        String[][] testData = {
918                { "0.001", "zero point zero zero one" },
919                { "0.0001", "zero point zero zero zero one" },
920                { "0.00001", "zero point zero zero zero zero one" },
921                { "0.000001", "zero point zero zero zero zero zero one" },
922                { "0.0000001", "zero point zero zero zero zero zero zero one" },
923                { "0.00000001", "zero point zero zero zero zero zero zero zero one" },
924                { "0.000000001", "zero point zero zero zero zero zero zero zero zero one" },
925                { "0.0000000001", "zero point zero zero zero zero zero zero zero zero zero one" },
926                { "0.00000000001", "zero point zero zero zero zero zero zero zero zero zero zero one" },
927                { "0.000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero one" },
928                { "0.0000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero one" },
929                { "0.00000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero one" },
930                { "0.000000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero zero one" },
931                { "10,000,000.001", "ten million point zero zero one" },
932                { "10,000,000.0001", "ten million point zero zero zero one" },
933                { "10,000,000.00001", "ten million point zero zero zero zero one" },
934                { "10,000,000.000001", "ten million point zero zero zero zero zero one" },
935                { "10,000,000.0000001", "ten million point zero zero zero zero zero zero one" },
936                { "10,000,000.00000001", "ten million point zero zero zero zero zero zero zero one" },
937                { "10,000,000.000000002", "ten million point zero zero zero zero zero zero zero zero two" },
938                { "10,000,000", "ten million" },
939                { "1,234,567,890.0987654", "one billion two hundred thirty-four million five hundred sixty-seven thousand eight hundred ninety point zero nine eight seven six five four" },
940                { "123,456,789.9876543", "one hundred twenty-three million four hundred fifty-six thousand seven hundred eighty-nine point nine eight seven six five four three" },
941                { "12,345,678.87654321", "twelve million three hundred forty-five thousand six hundred seventy-eight point eight seven six five four three two one" },
942                { "1,234,567.7654321", "one million two hundred thirty-four thousand five hundred sixty-seven point seven six five four three two one" },
943                { "123,456.654321", "one hundred twenty-three thousand four hundred fifty-six point six five four three two one" },
944                { "12,345.54321", "twelve thousand three hundred forty-five point five four three two one" },
945                { "1,234.4321", "one thousand two hundred thirty-four point four three two one" },
946                { "123.321", "one hundred twenty-three point three two one" },
947                { "0.0000000011754944", "zero point zero zero zero zero zero zero zero zero one one seven five four nine four four" },
948                { "0.000001175494351", "zero point zero zero zero zero zero one one seven five four nine four three five one" },
949        };
950
951        RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US, RuleBasedNumberFormat.SPELLOUT);
952        doTest(formatter, testData, true);
953    }
954
955    @Test
956    public void TestRuleSetDisplayName() {
957        /*
958         * Spellout rules for U.K. English.
959         * This was borrowed from the rule sets for TestRuleSetDisplayName()
960         */
961        final String ukEnglish =
962                "%simplified:\n"
963                        + "    -x: minus >>;\n"
964                        + "    x.x: << point >>;\n"
965                        + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
966                        + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
967                        + "        seventeen; eighteen; nineteen;\n"
968                        + "    20: twenty[->>];\n"
969                        + "    30: thirty[->>];\n"
970                        + "    40: forty[->>];\n"
971                        + "    50: fifty[->>];\n"
972                        + "    60: sixty[->>];\n"
973                        + "    70: seventy[->>];\n"
974                        + "    80: eighty[->>];\n"
975                        + "    90: ninety[->>];\n"
976                        + "    100: << hundred[ >>];\n"
977                        + "    1000: << thousand[ >>];\n"
978                        + "    1,000,000: << million[ >>];\n"
979                        + "    1,000,000,000,000: << billion[ >>];\n"
980                        + "    1,000,000,000,000,000: =#,##0=;\n"
981                        + "%alt-teens:\n"
982                        + "    =%simplified=;\n"
983                        + "    1000>: <%%alt-hundreds<[ >>];\n"
984                        + "    10,000: =%simplified=;\n"
985                        + "    1,000,000: << million[ >%simplified>];\n"
986                        + "    1,000,000,000,000: << billion[ >%simplified>];\n"
987                        + "    1,000,000,000,000,000: =#,##0=;\n"
988                        + "%%alt-hundreds:\n"
989                        + "    0: SHOULD NEVER GET HERE!;\n"
990                        + "    10: <%simplified< thousand;\n"
991                        + "    11: =%simplified= hundred>%%empty>;\n"
992                        + "%%empty:\n"
993                        + "    0:;"
994                        + "%ordinal:\n"
995                        + "    zeroth; first; second; third; fourth; fifth; sixth; seventh;\n"
996                        + "        eighth; ninth;\n"
997                        + "    tenth; eleventh; twelfth; thirteenth; fourteenth;\n"
998                        + "        fifteenth; sixteenth; seventeenth; eighteenth;\n"
999                        + "        nineteenth;\n"
1000                        + "    twentieth; twenty->>;\n"
1001                        + "    30: thirtieth; thirty->>;\n"
1002                        + "    40: fortieth; forty->>;\n"
1003                        + "    50: fiftieth; fifty->>;\n"
1004                        + "    60: sixtieth; sixty->>;\n"
1005                        + "    70: seventieth; seventy->>;\n"
1006                        + "    80: eightieth; eighty->>;\n"
1007                        + "    90: ninetieth; ninety->>;\n"
1008                        + "    100: <%simplified< hundredth; <%simplified< hundred >>;\n"
1009                        + "    1000: <%simplified< thousandth; <%simplified< thousand >>;\n"
1010                        + "    1,000,000: <%simplified< millionth; <%simplified< million >>;\n"
1011                        + "    1,000,000,000,000: <%simplified< billionth;\n"
1012                        + "        <%simplified< billion >>;\n"
1013                        + "    1,000,000,000,000,000: =#,##0=;"
1014                        + "%default:\n"
1015                        + "    -x: minus >>;\n"
1016                        + "    x.x: << point >>;\n"
1017                        + "    =%simplified=;\n"
1018                        + "    100: << hundred[ >%%and>];\n"
1019                        + "    1000: << thousand[ >%%and>];\n"
1020                        + "    100,000>>: << thousand[>%%commas>];\n"
1021                        + "    1,000,000: << million[>%%commas>];\n"
1022                        + "    1,000,000,000,000: << billion[>%%commas>];\n"
1023                        + "    1,000,000,000,000,000: =#,##0=;\n"
1024                        + "%%and:\n"
1025                        + "    and =%default=;\n"
1026                        + "    100: =%default=;\n"
1027                        + "%%commas:\n"
1028                        + "    ' and =%default=;\n"
1029                        + "    100: , =%default=;\n"
1030                        + "    1000: , <%default< thousand, >%default>;\n"
1031                        + "    1,000,000: , =%default=;"
1032                        + "%%lenient-parse:\n"
1033                        + "    & ' ' , ',' ;\n";
1034        ULocale.setDefault(ULocale.US);
1035        String[][] localizations = new String[][] {
1036            /* public rule sets*/
1037                {"%simplified", "%default", "%ordinal"},
1038            /* display names in "en_US" locale*/
1039                {"en_US", "Simplified", "Default", "Ordinal"},
1040            /* display names in "zh_Hans" locale*/
1041                {"zh_Hans", "\u7B80\u5316", "\u7F3A\u7701",  "\u5E8F\u5217"},
1042            /* display names in a fake locale*/
1043                {"foo_Bar_BAZ", "Simplified", "Default", "Ordinal"}
1044        };
1045
1046        //Construct RuleBasedNumberFormat by rule sets and localizations list
1047        RuleBasedNumberFormat formatter
1048                = new RuleBasedNumberFormat(ukEnglish, localizations, ULocale.US);
1049        RuleBasedNumberFormat f2= new RuleBasedNumberFormat(ukEnglish, localizations);
1050        assertTrue("Check the two formatters' equality", formatter.equals(f2));
1051
1052        //get displayName by name
1053        String[] ruleSetNames = formatter.getRuleSetNames();
1054        for (int i=0; i<ruleSetNames.length; i++) {
1055            logln("Rule set name: " + ruleSetNames[i]);
1056            String RSName_defLoc = formatter.getRuleSetDisplayName(ruleSetNames[i]);
1057            assertEquals("Display name in default locale", localizations[1][i+1], RSName_defLoc);
1058            String RSName_loc = formatter.getRuleSetDisplayName(ruleSetNames[i], ULocale.CHINA);
1059            assertEquals("Display name in Chinese", localizations[2][i+1], RSName_loc);
1060        }
1061
1062        // getDefaultRuleSetName
1063        String defaultRS = formatter.getDefaultRuleSetName();
1064        //you know that the default rule set is %simplified according to rule sets string ukEnglish
1065        assertEquals("getDefaultRuleSetName", "%simplified", defaultRS);
1066
1067        //get locales of localizations
1068        ULocale[] locales = formatter.getRuleSetDisplayNameLocales();
1069        for (int i=0; i<locales.length; i++) {
1070            logln(locales[i].getName());
1071        }
1072
1073        //get displayNames
1074        String[] RSNames_defLoc = formatter.getRuleSetDisplayNames();
1075        for (int i=0; i<RSNames_defLoc.length; i++) {
1076            assertEquals("getRuleSetDisplayNames in default locale", localizations[1][i+1], RSNames_defLoc[i]);
1077        }
1078
1079        String[] RSNames_loc = formatter.getRuleSetDisplayNames(ULocale.UK);
1080        for (int i=0; i<RSNames_loc.length; i++) {
1081            assertEquals("getRuleSetDisplayNames in English", localizations[1][i+1], RSNames_loc[i]);
1082        }
1083
1084        RSNames_loc = formatter.getRuleSetDisplayNames(ULocale.CHINA);
1085        for (int i=0; i<RSNames_loc.length; i++) {
1086            assertEquals("getRuleSetDisplayNames in Chinese", localizations[2][i+1], RSNames_loc[i]);
1087        }
1088
1089        RSNames_loc = formatter.getRuleSetDisplayNames(new ULocale("foo_Bar_BAZ"));
1090        for (int i=0; i<RSNames_loc.length; i++) {
1091            assertEquals("getRuleSetDisplayNames in fake locale", localizations[3][i+1], RSNames_loc[i]);
1092        }
1093    }
1094
1095    @Test
1096    public void TestAllLocales() {
1097        StringBuilder errors = new StringBuilder();
1098        String[] names = {
1099                " (spellout) ",
1100                " (ordinal) "
1101                //" (duration) " // English only
1102        };
1103        double[] numbers = {45.678, 1, 2, 10, 11, 100, 110, 200, 1000, 1111, -1111};
1104        int count = numbers.length;
1105        Random r = (count <= numbers.length ? null : createRandom());
1106
1107        for (ULocale loc : NumberFormat.getAvailableULocales()) {
1108            for (int j = 0; j < names.length; ++j) {
1109                RuleBasedNumberFormat fmt = new RuleBasedNumberFormat(loc, j+1);
1110                if (!loc.equals(fmt.getLocale(ULocale.ACTUAL_LOCALE))) {
1111                    // Skip the redundancy
1112                    break;
1113                }
1114
1115                for (int c = 0; c < count; c++) {
1116                    double n;
1117                    if (c < numbers.length) {
1118                        n = numbers[c];
1119                    } else {
1120                        n = (r.nextInt(10000) - 3000) / 16d;
1121                    }
1122
1123                    String s = fmt.format(n);
1124                    if (isVerbose()) {
1125                        logln(loc.getName() + names[j] + "success format: " + n + " -> " + s);
1126                    }
1127
1128                    try {
1129                        // RBNF parse is extremely slow when lenient option is enabled.
1130                        // non-lenient parse
1131                        fmt.setLenientParseMode(false);
1132                        Number num = fmt.parse(s);
1133                        if (isVerbose()) {
1134                            logln(loc.getName() + names[j] + "success parse: " + s + " -> " + num);
1135                        }
1136                        if (j != 0) {
1137                            // TODO: Fix the ordinal rules.
1138                            continue;
1139                        }
1140                        if (n != num.doubleValue()) {
1141                            errors.append("\n" + loc + names[j] + "got " + num + " expected " + n);
1142                        }
1143                    } catch (ParseException pe) {
1144                        String msg = loc.getName() + names[j] + "ERROR:" + pe.getMessage();
1145                        logln(msg);
1146                        errors.append("\n" + msg);
1147                    }
1148                }
1149            }
1150        }
1151        if (errors.length() > 0) {
1152            errln(errors.toString());
1153        }
1154    }
1155
1156    void doTest(RuleBasedNumberFormat formatter, String[][] testData,
1157                boolean testParsing) {
1158        //        NumberFormat decFmt = NumberFormat.getInstance(Locale.US);
1159        NumberFormat decFmt = new DecimalFormat("#,###.################");
1160        try {
1161            for (int i = 0; i < testData.length; i++) {
1162                String number = testData[i][0];
1163                String expectedWords = testData[i][1];
1164                if (isVerbose()) {
1165                    logln("test[" + i + "] number: " + number + " target: " + expectedWords);
1166                }
1167                Number num = decFmt.parse(number);
1168                String actualWords = formatter.format(num);
1169
1170                if (!actualWords.equals(expectedWords)) {
1171                    errln("Spot check format failed: for " + number + ", expected\n    "
1172                            + expectedWords + ", but got\n    " +
1173                            actualWords);
1174                }
1175                else if (testParsing) {
1176                    String actualNumber = decFmt.format(formatter
1177                            .parse(actualWords));
1178
1179                    if (!actualNumber.equals(number)) {
1180                        errln("Spot check parse failed: for " + actualWords +
1181                                ", expected " + number + ", but got " +
1182                                actualNumber);
1183                    }
1184                }
1185            }
1186        }
1187        catch (Throwable e) {
1188            e.printStackTrace();
1189            errln("Test failed with exception: " + e.toString());
1190        }
1191    }
1192
1193    /* Tests the method
1194     *      public boolean equals(Object that)
1195     */
1196    @Test
1197    public void TestEquals(){
1198        // Tests when "if (!(that instanceof RuleBasedNumberFormat))" is true
1199        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy");
1200        if (rbnf.equals("dummy") ||
1201                rbnf.equals(new Character('a')) ||
1202                rbnf.equals(new Object()) ||
1203                rbnf.equals(-1) ||
1204                rbnf.equals(0) ||
1205                rbnf.equals(1) ||
1206                rbnf.equals(-1.0) ||
1207                rbnf.equals(0.0) ||
1208                rbnf.equals(1.0))
1209        {
1210            errln("RuleBasedNumberFormat.equals(Object that) was suppose to " +
1211                    "be false for an invalid object.");
1212        }
1213
1214        // Tests when
1215        // "if (!locale.equals(that2.locale) || lenientParse != that2.lenientParse)"
1216        // is true
1217        RuleBasedNumberFormat rbnf1 = new RuleBasedNumberFormat("dummy", new Locale("en"));
1218        RuleBasedNumberFormat rbnf2 = new RuleBasedNumberFormat("dummy", new Locale("jp"));
1219        RuleBasedNumberFormat rbnf3 = new RuleBasedNumberFormat("dummy", new Locale("sp"));
1220        RuleBasedNumberFormat rbnf4 = new RuleBasedNumberFormat("dummy", new Locale("fr"));
1221
1222        if(rbnf1.equals(rbnf2) || rbnf1.equals(rbnf3) ||
1223                rbnf1.equals(rbnf4) || rbnf2.equals(rbnf3) ||
1224                rbnf2.equals(rbnf4) || rbnf3.equals(rbnf4)){
1225            errln("RuleBasedNumberFormat.equals(Object that) was suppose to " +
1226                    "be false for an invalid object.");
1227        }
1228
1229        if(!rbnf1.equals(rbnf1)){
1230            errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " +
1231                    "be false for an invalid object.");
1232        }
1233
1234        if(!rbnf2.equals(rbnf2)){
1235            errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " +
1236                    "be false for an invalid object.");
1237        }
1238
1239        if(!rbnf3.equals(rbnf3)){
1240            errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " +
1241                    "be false for an invalid object.");
1242        }
1243
1244        if(!rbnf4.equals(rbnf4)){
1245            errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " +
1246                    "be false for an invalid object.");
1247        }
1248
1249        RuleBasedNumberFormat rbnf5 = new RuleBasedNumberFormat("dummy", new Locale("en"));
1250        RuleBasedNumberFormat rbnf6 = new RuleBasedNumberFormat("dummy", new Locale("en"));
1251
1252        if(!rbnf5.equals(rbnf6)){
1253            errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " +
1254                    "be false for an invalid object.");
1255        }
1256        rbnf6.setLenientParseMode(true);
1257
1258        if(rbnf5.equals(rbnf6)){
1259            errln("RuleBasedNumberFormat.equals(Object that) was suppose to " +
1260                    "be false for an invalid object.");
1261        }
1262
1263        // Tests when "if (!ruleSets[i].equals(that2.ruleSets[i]))" is true
1264        RuleBasedNumberFormat rbnf7 = new RuleBasedNumberFormat("not_dummy", new Locale("en"));
1265        if(rbnf5.equals(rbnf7)){
1266            errln("RuleBasedNumberFormat.equals(Object that) was suppose to " +
1267                    "be false for an invalid object.");
1268        }
1269    }
1270
1271    /* Tests the method
1272     *      public ULocale[] getRuleSetDisplayNameLocales()
1273     */
1274    @Test
1275    public void TestGetRuleDisplayNameLocales(){
1276        // Tests when "if (ruleSetDisplayNames != null" is false
1277        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy");
1278        rbnf.getRuleSetDisplayNameLocales();
1279        if(rbnf.getRuleSetDisplayNameLocales() != null){
1280            errln("RuleBasedNumberFormat.getRuleDisplayNameLocales() was suppose to " +
1281                    "return null.");
1282        }
1283    }
1284
1285    /* Tests the method
1286     *      private String[] getNameListForLocale(ULocale loc)
1287     *      public String[] getRuleSetDisplayNames(ULocale loc)
1288     */
1289    @Test
1290    public void TestGetNameListForLocale(){
1291        // Tests when "if (names != null)" is false and
1292        //  "if (loc != null && ruleSetDisplayNames != null)" is false
1293        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy");
1294        rbnf.getRuleSetDisplayNames(null);
1295        try{
1296            rbnf.getRuleSetDisplayNames(null);
1297        } catch(Exception e){
1298            errln("RuleBasedNumberFormat.getRuleSetDisplayNames(ULocale loc) " +
1299                    "was not suppose to have an exception.");
1300        }
1301    }
1302
1303    /* Tests the method
1304     *      public String getRuleSetDisplayName(String ruleSetName, ULocale loc)
1305     */
1306    @Test
1307    public void TestGetRulesSetDisplayName(){
1308        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy");
1309        //rbnf.getRuleSetDisplayName("dummy", new ULocale("en_US"));
1310
1311        // Tests when "if (names != null) " is true
1312
1313        // Tests when the method throws an exception
1314        try{
1315            rbnf.getRuleSetDisplayName("", new ULocale("en_US"));
1316            errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " +
1317                    "was suppose to have an exception.");
1318        } catch(Exception ignored){}
1319
1320        try{
1321            rbnf.getRuleSetDisplayName("dummy", new ULocale("en_US"));
1322            errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " +
1323                    "was suppose to have an exception.");
1324        } catch(Exception ignored){}
1325    }
1326
1327    /* Test the method
1328     *      public void process(StringBuffer buf, NFRuleSet ruleSet)
1329     */
1330    @Test
1331    public void TestChineseProcess(){
1332        String ruleWithChinese =
1333            "%simplified:\n"
1334            + "    -x: minus >>;\n"
1335            + "    x.x: << point >>;\n"
1336            + "    zero; one; two; three; four; five; six; seven; eight; nine;\n"
1337            + "    ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1338            + "        seventeen; eighteen; nineteen;\n"
1339            + "    20: twenty[->>];\n"
1340            + "    30: thirty[->>];\n"
1341            + "    40: forty[->>];\n"
1342            + "    50: fifty[->>];\n"
1343            + "    60: sixty[->>];\n"
1344            + "    70: seventy[->>];\n"
1345            + "    80: eighty[->>];\n"
1346            + "    90: ninety[->>];\n"
1347            + "    100: << hundred[ >>];\n"
1348            + "    1000: << thousand[ >>];\n"
1349            + "    1,000,000: << million[ >>];\n"
1350            + "    1,000,000,000,000: << billion[ >>];\n"
1351            + "    1,000,000,000,000,000: =#,##0=;\n"
1352            + "%alt-teens:\n"
1353            + "    =%simplified=;\n"
1354            + "    1000>: <%%alt-hundreds<[ >>];\n"
1355            + "    10,000: =%simplified=;\n"
1356            + "    1,000,000: << million[ >%simplified>];\n"
1357            + "    1,000,000,000,000: << billion[ >%simplified>];\n"
1358            + "    1,000,000,000,000,000: =#,##0=;\n"
1359            + "%%alt-hundreds:\n"
1360            + "    0: SHOULD NEVER GET HERE!;\n"
1361            + "    10: <%simplified< thousand;\n"
1362            + "    11: =%simplified= hundred>%%empty>;\n"
1363            + "%%empty:\n"
1364            + "    0:;"
1365            + "%accounting:\n"
1366            + "    \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n"
1367            + "        \u842c; \u842c;\n"
1368            + "    \u842c; \u842c; \u842c; \u842c; \u842c;\n"
1369            + "        \u842c; \u842c; \u842c; \u842c;\n"
1370            + "        \u842c;\n"
1371            + "    twentieth; \u96f6|>>;\n"
1372            + "    30: \u96f6; \u96f6|>>;\n"
1373            + "    40: \u96f6; \u96f6|>>;\n"
1374            + "    50: \u96f6; \u96f6|>>;\n"
1375            + "    60: \u96f6; \u96f6|>>;\n"
1376            + "    70: \u96f6; \u96f6|>>;\n"
1377            + "    80: \u96f6; \u96f6|>>;\n"
1378            + "    90: \u96f6; \u96f6|>>;\n"
1379            + "    100: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n"
1380            + "    1000: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n"
1381            + "    1,000,000: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n"
1382            + "    1,000,000,000,000: <%simplified< \u96f6;\n"
1383            + "        <%simplified< \u96f6 >>;\n"
1384            + "    1,000,000,000,000,000: =#,##0=;"
1385            + "%default:\n"
1386            + "    -x: minus >>;\n"
1387            + "    x.x: << point >>;\n"
1388            + "    =%simplified=;\n"
1389            + "    100: << hundred[ >%%and>];\n"
1390            + "    1000: << thousand[ >%%and>];\n"
1391            + "    100,000>>: << thousand[>%%commas>];\n"
1392            + "    1,000,000: << million[>%%commas>];\n"
1393            + "    1,000,000,000,000: << billion[>%%commas>];\n"
1394            + "    1,000,000,000,000,000: =#,##0=;\n"
1395            + "%%and:\n"
1396            + "    and =%default=;\n"
1397            + "    100: =%default=;\n"
1398            + "%%commas:\n"
1399            + "    ' and =%default=;\n"
1400            + "    100: , =%default=;\n"
1401            + "    1000: , <%default< thousand, >%default>;\n"
1402            + "    1,000,000: , =%default=;"
1403            + "%traditional:\n"
1404            + "    -x: \u3007| >>;\n"
1405            + "    x.x: << \u9ede >>;\n"
1406            + "    \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n"
1407            + "    \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n"
1408            + "        \u842c; \u842c; \u842c;\n"
1409            + "    20: \u842c[->>];\n"
1410            + "    30: \u842c[->>];\n"
1411            + "    40: \u842c[->>];\n"
1412            + "    50: \u842c[->>];\n"
1413            + "    60: \u842c[->>];\n"
1414            + "    70: \u842c[->>];\n"
1415            + "    80: \u842c[->>];\n"
1416            + "    90: \u842c[->>];\n"
1417            + "    100: << \u842c[ >>];\n"
1418            + "    1000: << \u842c[ >>];\n"
1419            + "    1,000,000: << \u842c[ >>];\n"
1420            + "    1,000,000,000,000: << \u842c[ >>];\n"
1421            + "    1,000,000,000,000,000: =#,##0=;\n"
1422            + "%time:\n"
1423            + "    =0= sec.;\n"
1424            + "    60: =%%min-sec=;\n"
1425            + "    3600: =%%hr-min-sec=;\n"
1426            + "%%min-sec:\n"
1427            + "    0: *=00=;\n"
1428            + "    60/60: <0<>>;\n"
1429            + "%%hr-min-sec:\n"
1430            + "    0: *=00=;\n"
1431            + "    60/60: <00<>>;\n"
1432            + "    3600/60: <#,##0<:>>>;\n"
1433            + "%%post-process:android.icu.text.RBNFChinesePostProcessor\n";
1434
1435        RuleBasedNumberFormat rbnf =  new RuleBasedNumberFormat(ruleWithChinese, ULocale.CHINESE);
1436        String[] ruleNames = rbnf.getRuleSetNames();
1437        try{
1438            // Test with "null" rules
1439            rbnf.format(0.0, null);
1440            errln("This was suppose to return an exception for a null format");
1441        } catch(Exception e){}
1442        for(int i=0; i<ruleNames.length; i++){
1443            try{
1444                rbnf.format(-123450.6789,ruleNames[i]);
1445            } catch(Exception e){
1446                errln("RBNFChinesePostProcessor was not suppose to return an exception " +
1447                        "when being formatted with parameters 0.0 and " + ruleNames[i]);
1448            }
1449        }
1450    }
1451
1452    @Test
1453    public void TestSetDecimalFormatSymbols() {
1454        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(Locale.ENGLISH, RuleBasedNumberFormat.ORDINAL);
1455
1456        DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.ENGLISH);
1457
1458        double number = 1001;
1459
1460        String[] expected = { "1,001st", "1&001st" };
1461
1462        String result = rbnf.format(number);
1463        if (!result.equals(expected[0])) {
1464            errln("Format Error - Got: " + result + " Expected: " + expected[0]);
1465        }
1466
1467        /* Set new symbol for testing */
1468        dfs.setGroupingSeparator('&');
1469        rbnf.setDecimalFormatSymbols(dfs);
1470
1471        result = rbnf.format(number);
1472        if (!result.equals(expected[1])) {
1473            errln("Format Error - Got: " + result + " Expected: " + expected[1]);
1474        }
1475    }
1476
1477    @Test
1478    public void TestContext() {
1479        class TextContextItem {
1480            public String locale;
1481            public int format;
1482            public DisplayContext context;
1483            public double value;
1484            public String expectedResult;
1485            // Simple constructor
1486            public TextContextItem(String loc, int fmt, DisplayContext ctxt, double val, String expRes) {
1487                locale = loc;
1488                format = fmt;
1489                context = ctxt;
1490                value = val;
1491                expectedResult = expRes;
1492            }
1493        }
1494        final TextContextItem[] items = {
1495                new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
1496                new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "Ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
1497                new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,       123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
1498                new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE,            123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
1499                new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    123.45, "one hundred twenty-three point four five" ),
1500                new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "One hundred twenty-three point four five" ),
1501                new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU,       123.45, "One hundred twenty-three point four five" ),
1502                new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE,            123.45, "One hundred twenty-three point four five" ),
1503        };
1504        for (TextContextItem item: items) {
1505            ULocale locale = new ULocale(item.locale);
1506            RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(locale, item.format);
1507            rbnf.setContext(item.context);
1508            String result = rbnf.format(item.value, rbnf.getDefaultRuleSetName());
1509            if (!result.equals(item.expectedResult)) {
1510                errln("Error for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result);
1511            }
1512            RuleBasedNumberFormat rbnfClone = (RuleBasedNumberFormat)rbnf.clone();
1513            if (!rbnfClone.equals(rbnf)) {
1514                errln("Error for locale " + item.locale + ", context " + item.context + ", rbnf.clone() != rbnf");
1515            } else {
1516                result = rbnfClone.format(item.value, rbnfClone.getDefaultRuleSetName());
1517                if (!result.equals(item.expectedResult)) {
1518                    errln("Error with clone for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result);
1519                }
1520            }
1521        }
1522    }
1523
1524    @Test
1525    public void TestInfinityNaN() {
1526        String enRules = "%default:"
1527                + "-x: minus >>;"
1528                + "Inf: infinite;"
1529                + "NaN: not a number;"
1530                + "0: =#,##0=;";
1531        RuleBasedNumberFormat enFormatter = new RuleBasedNumberFormat(enRules, ULocale.ENGLISH);
1532        String[][] enTestData = {
1533                {"1", "1"},
1534                {"\u221E", "infinite"},
1535                {"-\u221E", "minus infinite"},
1536                {"NaN", "not a number"},
1537
1538        };
1539
1540        doTest(enFormatter, enTestData, true);
1541
1542        // Test the default behavior when the rules are undefined.
1543        enRules = "%default:"
1544                + "-x: ->>;"
1545                + "0: =#,##0=;";
1546        enFormatter = new RuleBasedNumberFormat(enRules, ULocale.ENGLISH);
1547        String[][] enDefaultTestData = {
1548                {"1", "1"},
1549                {"\u221E", "∞"},
1550                {"-\u221E", "-∞"},
1551                {"NaN", "NaN"},
1552
1553        };
1554
1555        doTest(enFormatter, enDefaultTestData, true);
1556    }
1557
1558    @Test
1559    public void TestVariableDecimalPoint() {
1560        String enRules = "%spellout-numbering:"
1561                + "-x: minus >>;"
1562                + "x.x: << point >>;"
1563                + "x,x: << comma >>;"
1564                + "0.x: xpoint >>;"
1565                + "0,x: xcomma >>;"
1566                + "0: zero;"
1567                + "1: one;"
1568                + "2: two;"
1569                + "3: three;"
1570                + "4: four;"
1571                + "5: five;"
1572                + "6: six;"
1573                + "7: seven;"
1574                + "8: eight;"
1575                + "9: nine;";
1576        RuleBasedNumberFormat enFormatter = new RuleBasedNumberFormat(enRules, ULocale.ENGLISH);
1577        String[][] enTestPointData = {
1578                {"1.1", "one point one"},
1579                {"1.23", "one point two three"},
1580                {"0.4", "xpoint four"},
1581        };
1582        doTest(enFormatter, enTestPointData, true);
1583        DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(ULocale.ENGLISH);
1584        decimalFormatSymbols.setDecimalSeparator(',');
1585        enFormatter.setDecimalFormatSymbols(decimalFormatSymbols);
1586        String[][] enTestCommaData = {
1587                {"1.1", "one comma one"},
1588                {"1.23", "one comma two three"},
1589                {"0.4", "xcomma four"},
1590        };
1591        doTest(enFormatter, enTestCommaData, true);
1592    }
1593
1594    @Test
1595    public void TestRounding() {
1596        RuleBasedNumberFormat enFormatter = new RuleBasedNumberFormat(ULocale.ENGLISH, RuleBasedNumberFormat.SPELLOUT);
1597        String[][] enTestFullData = {
1598                {"0", "zero"},
1599                {"0.4", "zero point four"},
1600                {"0.49", "zero point four nine"},
1601                {"0.5", "zero point five"},
1602                {"0.51", "zero point five one"},
1603                {"0.99", "zero point nine nine"},
1604                {"1", "one"},
1605                {"1.01", "one point zero one"},
1606                {"1.49", "one point four nine"},
1607                {"1.5", "one point five"},
1608                {"1.51", "one point five one"},
1609                {"450359962737049.6", "four hundred fifty trillion three hundred fifty-nine billion nine hundred sixty-two million seven hundred thirty-seven thousand forty-nine point six"}, // 2^52 / 10
1610                {"450359962737049.7", "four hundred fifty trillion three hundred fifty-nine billion nine hundred sixty-two million seven hundred thirty-seven thousand forty-nine point seven"}, // 2^52 + 1 / 10
1611        };
1612        doTest(enFormatter, enTestFullData, false);
1613
1614        enFormatter.setMaximumFractionDigits(0);
1615        enFormatter.setRoundingMode(BigDecimal.ROUND_HALF_EVEN);
1616        String[][] enTestIntegerData = {
1617                {"0", "zero"},
1618                {"0.4", "zero"},
1619                {"0.49", "zero"},
1620                {"0.5", "zero"},
1621                {"0.51", "one"},
1622                {"0.99", "one"},
1623                {"1", "one"},
1624                {"1.01", "one"},
1625                {"1.49", "one"},
1626                {"1.5", "two"},
1627                {"1.51", "two"},
1628        };
1629        doTest(enFormatter, enTestIntegerData, false);
1630
1631        enFormatter.setMaximumFractionDigits(1);
1632        enFormatter.setRoundingMode(BigDecimal.ROUND_HALF_EVEN);
1633        String[][] enTestTwoDigitsData = {
1634                {"0", "zero"},
1635                {"0.04", "zero"},
1636                {"0.049", "zero"},
1637                {"0.05", "zero"},
1638                {"0.051", "zero point one"},
1639                {"0.099", "zero point one"},
1640                {"10.11", "ten point one"},
1641                {"10.149", "ten point one"},
1642                {"10.15", "ten point two"},
1643                {"10.151", "ten point two"},
1644        };
1645        doTest(enFormatter, enTestTwoDigitsData, false);
1646
1647        enFormatter.setMaximumFractionDigits(3);
1648        enFormatter.setRoundingMode(BigDecimal.ROUND_DOWN);
1649        String[][] enTestThreeDigitsDownData = {
1650                {"4.3", "four point three"}, // Not 4.299!
1651        };
1652        doTest(enFormatter, enTestThreeDigitsDownData, false);
1653    }
1654
1655    @Test
1656    public void testLargeNumbers() {
1657        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ULocale.US, RuleBasedNumberFormat.SPELLOUT);
1658
1659        String[][] enTestFullData = {
1660                {"-9007199254740991", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
1661                {"9007199254740991", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
1662                {"-9007199254740992", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
1663                {"9007199254740992", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
1664                {"9999999999999998", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-eight"},
1665                {"9999999999999999", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
1666                {"999999999999999999", "nine hundred ninety-nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
1667                {"1000000000000000000", "1,000,000,000,000,000,000"}, // The rules don't go to 1 quintillion yet
1668                {"-9223372036854775809", "-9,223,372,036,854,775,809"}, // We've gone beyond 64-bit precision
1669                {"-9223372036854775808", "-9,223,372,036,854,775,808"}, // We've gone beyond +64-bit precision
1670                {"-9223372036854775807", "minus 9,223,372,036,854,775,807"}, // Minimum 64-bit precision
1671                {"-9223372036854775806", "minus 9,223,372,036,854,775,806"}, // Minimum 64-bit precision + 1
1672                {"9223372036854774111", "9,223,372,036,854,774,111"}, // Below 64-bit precision
1673                {"9223372036854774999", "9,223,372,036,854,774,999"}, // Below 64-bit precision
1674                {"9223372036854775000", "9,223,372,036,854,775,000"}, // Below 64-bit precision
1675                {"9223372036854775806", "9,223,372,036,854,775,806"}, // Maximum 64-bit precision - 1
1676                {"9223372036854775807", "9,223,372,036,854,775,807"}, // Maximum 64-bit precision
1677                {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
1678        };
1679        doTest(rbnf, enTestFullData, false);
1680    }
1681
1682    @Test
1683    public void testCompactDecimalFormatStyle() {
1684        // This is not a common use case, but we're testing it anyway.
1685        final String numberPattern = "=###0.#####=;"
1686                + "1000: <###0.00< K;"
1687                + "1000000: <###0.00< M;"
1688                + "1000000000: <###0.00< B;"
1689                + "1000000000000: <###0.00< T;"
1690                + "1000000000000000: <###0.00< Q;";
1691        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(numberPattern, ULocale.US);
1692
1693        String[][] enTestFullData = {
1694                {"1000", "1.00 K"},
1695                {"1234", "1.23 K"},
1696                {"999994", "999.99 K"},
1697                {"999995", "1000.00 K"},
1698                {"1000000", "1.00 M"},
1699                {"1200000", "1.20 M"},
1700                {"1200000000", "1.20 B"},
1701                {"1200000000000", "1.20 T"},
1702                {"1200000000000000", "1.20 Q"},
1703                {"4503599627370495", "4.50 Q"},
1704                {"4503599627370496", "4.50 Q"},
1705                {"8990000000000000", "8.99 Q"},
1706                {"9008000000000000", "9.00 Q"}, // Number doesn't precisely fit into a double
1707                {"9456000000000000", "9.00 Q"},  // Number doesn't precisely fit into a double
1708                {"10000000000000000", "10.00 Q"},  // Number doesn't precisely fit into a double
1709                {"9223372036854775807", "9223.00 Q"}, // Maximum 64-bit precision
1710                {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
1711        };
1712        doTest(rbnf, enTestFullData, false);
1713    }
1714
1715    private void assertEquals(String expected, String result) {
1716        if (!expected.equals(result)) {
1717            errln("Expected: " + expected + " Got: " + result);
1718        }
1719    }
1720
1721    @Test
1722    public void testRoundingUnrealNumbers() {
1723        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ULocale.US, RuleBasedNumberFormat.SPELLOUT);
1724        rbnf.setRoundingMode(BigDecimal.ROUND_HALF_UP);
1725        rbnf.setMaximumFractionDigits(3);
1726        assertEquals("zero point one", rbnf.format(0.1));
1727        assertEquals("zero point zero zero one", rbnf.format(0.0005));
1728        assertEquals("infinity", rbnf.format(Double.POSITIVE_INFINITY));
1729        assertEquals("not a number", rbnf.format(Double.NaN));
1730    }
1731}
1732