17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2007-2014, International Business Machines Corporation and
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved.
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.dev.test.format;
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParsePosition;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashMap;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashSet;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map;
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.test.TestFmwk;
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.DecimalFormat;
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.DecimalFormatSymbols;
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.MessageFormat;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.NumberFormat;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralFormat;
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules;
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.PluralType;
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.SampleType;
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale;
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author tschumann (Tim Schumann)
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class PluralFormatUnitTest extends TestFmwk {
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static void main(String[] args) throws Exception {
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        new PluralFormatUnitTest().run(args);
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestConstructor() {
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Test correct formatting of numbers.
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat plFmts[] = new PluralFormat[10];
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[0] = new PluralFormat();
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[0].applyPattern("other{#}");
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[1] = new PluralFormat(PluralRules.DEFAULT);
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[1].applyPattern("other{#}");
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[2] = new PluralFormat(PluralRules.DEFAULT, "other{#}");
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[3] = new PluralFormat("other{#}");
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[4] = new PluralFormat(ULocale.getDefault());
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[4].applyPattern("other{#}");
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[5] = new PluralFormat(ULocale.getDefault(), PluralRules.DEFAULT);
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[5].applyPattern("other{#}");
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[6] = new PluralFormat(ULocale.getDefault(),
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                PluralRules.DEFAULT,
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "other{#}");
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[7] = new PluralFormat(ULocale.getDefault(), "other{#}");
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Constructors with Java Locale
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[8] = new PluralFormat(Locale.getDefault());
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[8].applyPattern("other{#}");
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[9] = new PluralFormat(Locale.getDefault(), PluralRules.DEFAULT);
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmts[9].applyPattern("other{#}");
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // These plural formats should produce the same output as a
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // NumberFormat for the default locale.
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        NumberFormat numberFmt = NumberFormat.getInstance(ULocale.getDefault());
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int n = 1; n < 13; n++) {
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String result = numberFmt.format(n);
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int k = 0; k < plFmts.length; ++k) {
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                this.assertEquals("PluralFormat's output is not as expected",
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        result, plFmts[k].format(n));
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Test some bigger numbers.
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int n = 100; n < 113; n++) {
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String result = numberFmt.format(n*n);
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int k = 0; k < plFmts.length; ++k) {
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                this.assertEquals("PluralFormat's output is not as expected",
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        result, plFmts[k].format(n*n));
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestApplyPatternAndFormat() {
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Create rules for testing.
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralRules oddAndEven =  PluralRules.createRules("odd: n mod 2 is 1");
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Test full specified case for testing RuleSet
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plfOddAndEven = new PluralFormat(oddAndEven);
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plfOddAndEven.applyPattern("odd{# is odd.} other{# is even.}");
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Test fall back to other.
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plfOddOrEven = new PluralFormat(oddAndEven);
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plfOddOrEven.applyPattern("other{# is odd or even.}");
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            NumberFormat numberFormat =
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    NumberFormat.getInstance(ULocale.getDefault());
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 0; i < 22; ++i) {
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                assertEquals("Fallback to other gave wrong results",
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        numberFormat.format(i) + " is odd or even.",
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        plfOddOrEven.format(i));
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                assertEquals("Fully specified PluralFormat gave wrong results",
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        numberFormat.format(i) + ((i%2 == 1) ?  " is odd."
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                :  " is even."),
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                plfOddAndEven.format(i));
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // ICU 4.8 does not check for duplicate keywords any more.
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat pf = new PluralFormat(ULocale.ENGLISH, oddAndEven,
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "odd{foo} odd{bar} other{foobar}");
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("should use first occurrence of the 'odd' keyword", "foo", pf.format(1));
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            pf.applyPattern("odd{foo} other{bar} other{foobar}");
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("should use first occurrence of the 'other' keyword", "bar", pf.format(2));
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // This sees the first "other" before calling the PluralSelector which then selects "other".
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            pf.applyPattern("other{foo} odd{bar} other{foobar}");
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("should use first occurrence of the 'other' keyword", "foo", pf.format(2));
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // omit other keyword.
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("odd{foo}");
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("Not defining plural case other should result in an " +
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "exception but did not.");
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }catch (IllegalArgumentException e){}
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // ICU 4.8 does not check for unknown keywords any more.
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat pf = new PluralFormat(ULocale.ENGLISH, oddAndEven, "otto{foo} other{bar}");
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("should ignore unknown keywords", "bar", pf.format(1));
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Test invalid keyword.
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("*odd{foo} other{bar}");
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("Defining a message for an invalid keyword should result in " +
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "an exception but did not.");
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }catch (IllegalArgumentException e){}
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Test invalid syntax
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        //   -- comma between keyword{message} clauses
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        //   -- space in keywords
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        //   -- keyword{message1}{message2}
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("odd{foo},other{bar}");
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("Separating keyword{message} items with other characters " +
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "than space should provoke an exception but did not.");
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }catch (IllegalArgumentException e){}
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("od d{foo} other{bar}");
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("Spaces inside keywords should provoke an exception but " +
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "did not.");
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }catch (IllegalArgumentException e){}
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("odd{foo}{foobar}other{foo}");
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("Defining multiple messages after a keyword should provoke " +
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "an exception but did not.");
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }catch (IllegalArgumentException e){}
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check that nested format is preserved.
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("odd{The number {0, number, #.#0} is odd.}" +
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "other{The number {0, number, #.#0} is even.}");
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 1; i < 3; ++i) {
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                assertEquals("format did not preserve a nested format string.",
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        ((i % 2 == 1) ?
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                "The number {0, number, #.#0} is odd."
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                : "The number {0, number, #.#0} is even."),
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                plFmt.format(i));
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check that a pound sign in curly braces is preserved.
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat plFmt = new PluralFormat(oddAndEven);
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.applyPattern("odd{The number {1,number,#} is odd.}" +
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "other{The number {2,number,#} is even.}");
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 1; i < 3; ++i) {
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                assertEquals("format did not preserve # inside curly braces.",
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        ((i % 2 == 1) ? "The number {1,number,#} is odd."
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                : "The number {2,number,#} is even."),
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                plFmt.format(i));
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestSamples() {
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Map<ULocale,Set<ULocale>> same = new LinkedHashMap();
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (ULocale locale : PluralRules.getAvailableULocales()) {
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ULocale otherLocale = PluralRules.getFunctionalEquivalent(locale, null);
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Set<ULocale> others = same.get(otherLocale);
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (others == null) same.put(otherLocale, others = new LinkedHashSet());
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            others.add(locale);
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            continue;
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (ULocale locale0 : same.keySet()) {
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralRules rules = PluralRules.forLocale(locale0);
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String localeName = locale0.toString().length() == 0 ? "root" : locale0.toString();
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            logln(localeName + "\t=\t" + same.get(locale0));
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            logln(localeName + "\ttoString\t" + rules.toString());
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Set<String> keywords = rules.getKeywords();
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (String keyword : keywords) {
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Collection<Double> list = rules.getSamples(keyword);
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (list.size() == 0) {
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // if there aren't any integer samples, get the decimal ones.
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    list = rules.getSamples(keyword, SampleType.DECIMAL);
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (list == null || list.size() == 0) {
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    errln("Empty list for " + localeName + " : " + keyword);
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    logln("\t" + localeName + " : " + keyword + " ; " + list);
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestSetLocale() {
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Create rules for testing.
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralRules oddAndEven = PluralRules.createRules("odd__: n mod 2 is 1");
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat plFmt = new PluralFormat(oddAndEven);
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmt.applyPattern("odd__{odd} other{even}");
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmt.setLocale(ULocale.ENGLISH);
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check that pattern gets deleted.
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        NumberFormat nrFmt = NumberFormat.getInstance(ULocale.ENGLISH);
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("pattern was not resetted by setLocale() call.",
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                nrFmt.format(5),
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                plFmt.format(5));
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check that rules got updated.
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmt.applyPattern("odd__{odd} other{even}");
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("SetLocale should reset rules but did not.", "even", plFmt.format(1));
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmt.applyPattern("one{one} other{not one}");
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < 20; ++i) {
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("Wrong ruleset loaded by setLocale()",
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ((i==1) ? "one" : "not one"),
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    plFmt.format(i));
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestParse() {
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat plFmt = new PluralFormat("other{test}");
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.parse("test", new ParsePosition(0));
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("parse() should throw an UnsupportedOperationException but " +
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "did not");
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch (UnsupportedOperationException e) {
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        plFmt = new PluralFormat("other{test}");
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            plFmt.parseObject("test", new ParsePosition(0));
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            errln("parse() should throw an UnsupportedOperationException but " +
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    "did not");
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch (UnsupportedOperationException e) {
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestPattern() {
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Object[] args = { "acme", null };
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // ICU 4.8 PluralFormat does not trim() its pattern any more.
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // None of the other *Format classes do.
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String pat = "  one {one ''widget} other {# widgets}  ";
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PluralFormat pf = new PluralFormat(pat);
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("should not trim() the pattern", pat, pf.toPattern());
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        MessageFormat pfmt = new MessageFormat("The disk ''{0}'' contains {1, plural,  one {one ''''{1, number, #.0}'''' widget} other {# widgets}}.");
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        logln("");
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < 3; ++i) {
2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            args[1] = new Integer(i);
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            logln(pfmt.format(args));
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* ICU 4.8 returns null instead of a choice/plural/select Format object
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * (because it does not create an object for any "complex" argument).
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat pf = (PluralFormat)pfmt.getFormatsByArgumentIndex()[1];
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        logln(pf.toPattern());
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        logln(pfmt.toPattern());
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        MessageFormat pfmt2 = new MessageFormat(pfmt.toPattern());
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("message formats are equal", pfmt, pfmt2);
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestExtendedPluralFormat() {
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String[] targets = {
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There are no widgets.",
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is one widget.",
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is a bling widget and one other widget.",
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is a bling widget and 2 other widgets.",
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is a bling widget and 3 other widgets.",
3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "Widgets, five (5-1=4) there be.",
3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is a bling widget and 5 other widgets.",
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "There is a bling widget and 6 other widgets.",
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        };
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String pluralStyle =
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "offset:1.0 "
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        + "=0 {There are no widgets.} "
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        + "=1.0 {There is one widget.} "
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        + "=5 {Widgets, five (5-1=#) there be.} "
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        + "one {There is a bling widget and one other widget.} "
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        + "other {There is a bling widget and # other widgets.}";
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat pf = new PluralFormat(ULocale.ENGLISH, pluralStyle);
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        MessageFormat mf = new MessageFormat("{0,plural," + pluralStyle + "}", ULocale.ENGLISH);
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Integer args[] = new Integer[1];
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i <= 7; ++i) {
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String result = pf.format(i);
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("PluralFormat.format(value " + i + ")", targets[i], result);
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            args[0] = i;
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result = mf.format(args);
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            assertEquals("MessageFormat.format(value " + i + ")", targets[i], result);
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Try explicit values after keywords.
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pf.applyPattern("other{zz}other{yy}one{xx}one{ww}=1{vv}=1{uu}");
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("should find first matching *explicit* value", "vv", pf.format(1));
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestExtendedPluralFormatParsing() {
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String[] failures = {
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "offset:1..0 =0 {Foo}",
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "offset:1.0 {Foo}",
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "=0= {Foo}",
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "=0 {Foo} =0.0 {Bar}",
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                " = {Foo}",
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        };
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (String fmt : failures) {
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                new PluralFormat(fmt);
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                fail("expected exception when parsing '" + fmt + "'");
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } catch (IllegalArgumentException e) {
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // ok
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestOrdinalFormat() {
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String pattern = "one{#st file}two{#nd file}few{#rd file}other{#th file}";
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL, pattern);
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("PluralFormat.format(321)", "321st file", pf.format(321));
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("PluralFormat.format(22)", "22nd file", pf.format(22));
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("PluralFormat.format(3)", "3rd file", pf.format(3));
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Code coverage: Use the other new-for-PluralType constructor as well.
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL);
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pf.applyPattern(pattern);
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("PluralFormat.format(456)", "456th file", pf.format(456));
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("PluralFormat.format(111)", "111th file", pf.format(111));
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void TestDecimals() {
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Simple number replacement.
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat pf = new PluralFormat(ULocale.ENGLISH, "one{one meter}other{# meters}");
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("simple format(1)", "one meter", pf.format(1));
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("simple format(1.5)", "1.5 meters", pf.format(1.5));
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PluralFormat pf2 = new PluralFormat(ULocale.ENGLISH,
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                "offset:1 one{another meter}other{another # meters}");
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pf2.setNumberFormat(new DecimalFormat("0.0", new DecimalFormatSymbols(ULocale.ENGLISH)));
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("offset-decimals format(1)", "another 0.0 meters", pf2.format(1));
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("offset-decimals format(2)", "another 1.0 meters", pf2.format(2));
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assertEquals("offset-decimals format(2.5)", "another 1.5 meters", pf2.format(2.5));
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
372