Home | History | Annotate | Download | only in format
      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) 2007-2016, International Business Machines Corporation and
      7  * others. All Rights Reserved.
      8  *******************************************************************************
      9  */
     10 
     11 package android.icu.dev.test.format;
     12 
     13 import java.text.FieldPosition;
     14 import java.text.ParsePosition;
     15 import java.util.Collection;
     16 import java.util.LinkedHashMap;
     17 import java.util.LinkedHashSet;
     18 import java.util.Locale;
     19 import java.util.Map;
     20 import java.util.Set;
     21 
     22 import org.junit.Test;
     23 
     24 import android.icu.dev.test.TestFmwk;
     25 import android.icu.text.DecimalFormat;
     26 import android.icu.text.DecimalFormatSymbols;
     27 import android.icu.text.MessageFormat;
     28 import android.icu.text.NumberFormat;
     29 import android.icu.text.PluralFormat;
     30 import android.icu.text.PluralRules;
     31 import android.icu.text.PluralRules.PluralType;
     32 import android.icu.text.PluralRules.SampleType;
     33 import android.icu.util.ULocale;
     34 
     35 /**
     36  * @author tschumann (Tim Schumann)
     37  *
     38  */
     39 public class PluralFormatUnitTest extends TestFmwk {
     40     @Test
     41     public void TestConstructor() {
     42         // Test correct formatting of numbers.
     43         PluralFormat plFmts[] = new PluralFormat[10];
     44         plFmts[0] = new PluralFormat();
     45         plFmts[0].applyPattern("other{#}");
     46         plFmts[1] = new PluralFormat(PluralRules.DEFAULT);
     47         plFmts[1].applyPattern("other{#}");
     48         plFmts[2] = new PluralFormat(PluralRules.DEFAULT, "other{#}");
     49         plFmts[3] = new PluralFormat("other{#}");
     50         plFmts[4] = new PluralFormat(ULocale.getDefault());
     51         plFmts[4].applyPattern("other{#}");
     52         plFmts[5] = new PluralFormat(ULocale.getDefault(), PluralRules.DEFAULT);
     53         plFmts[5].applyPattern("other{#}");
     54         plFmts[6] = new PluralFormat(ULocale.getDefault(),
     55                 PluralRules.DEFAULT,
     56                 "other{#}");
     57         plFmts[7] = new PluralFormat(ULocale.getDefault(), "other{#}");
     58 
     59         // Constructors with Java Locale
     60         plFmts[8] = new PluralFormat(Locale.getDefault());
     61         plFmts[8].applyPattern("other{#}");
     62         plFmts[9] = new PluralFormat(Locale.getDefault(), PluralRules.DEFAULT);
     63         plFmts[9].applyPattern("other{#}");
     64 
     65         // These plural formats should produce the same output as a
     66         // NumberFormat for the default locale.
     67         NumberFormat numberFmt = NumberFormat.getInstance(ULocale.getDefault());
     68         for (int n = 1; n < 13; n++) {
     69             String result = numberFmt.format(n);
     70             for (int k = 0; k < plFmts.length; ++k) {
     71                 TestFmwk.assertEquals("PluralFormat's output is not as expected",
     72                         result, plFmts[k].format(n));
     73             }
     74         }
     75         // Test some bigger numbers.
     76         // Coverage: Use the format(Object, ...) version.
     77         StringBuffer sb = new StringBuffer();
     78         FieldPosition ignore = new FieldPosition(-1);
     79         for (int n = 100; n < 113; n++) {
     80             String result = numberFmt.format(n*n);
     81             for (int k = 0; k < plFmts.length; ++k) {
     82                 sb.delete(0, sb.length());
     83                 String pfResult = plFmts[k].format(Long.valueOf(n*n), sb, ignore).toString();
     84                 TestFmwk.assertEquals("PluralFormat's output is not as expected", result, pfResult);
     85             }
     86         }
     87     }
     88 
     89     public void TestEquals() {
     90         // There is neither clone() nor a copy constructor.
     91         PluralFormat de_fee_1 = new PluralFormat(ULocale.GERMAN, PluralType.CARDINAL, "other{fee}");
     92         PluralFormat de_fee_2 = new PluralFormat(ULocale.GERMAN, PluralType.CARDINAL, "other{fee}");
     93         PluralFormat de_fi = new PluralFormat(ULocale.GERMAN, PluralType.CARDINAL, "other{fi}");
     94         PluralFormat fr_fee = new PluralFormat(ULocale.FRENCH, PluralType.CARDINAL, "other{fee}");
     95         assertTrue("different de_fee objects", de_fee_1 != de_fee_2);
     96         assertTrue("equal de_fee objects", de_fee_1.equals(de_fee_2));
     97         assertFalse("different pattern strings", de_fee_1.equals(de_fi));
     98         assertFalse("different locales", de_fee_1.equals(fr_fee));
     99     }
    100 
    101     public void TestApplyPatternAndFormat() {
    102         // Create rules for testing.
    103         PluralRules oddAndEven =  PluralRules.createRules("odd: n mod 2 is 1");
    104         {
    105             // Test full specified case for testing RuleSet
    106             PluralFormat plfOddAndEven = new PluralFormat(oddAndEven);
    107             plfOddAndEven.applyPattern("odd{# is odd.} other{# is even.}");
    108 
    109             // Test fall back to other.
    110             PluralFormat plfOddOrEven = new PluralFormat(oddAndEven);
    111             plfOddOrEven.applyPattern("other{# is odd or even.}");
    112 
    113             NumberFormat numberFormat =
    114                     NumberFormat.getInstance(ULocale.getDefault());
    115             for (int i = 0; i < 22; ++i) {
    116                 assertEquals("Fallback to other gave wrong results",
    117                         numberFormat.format(i) + " is odd or even.",
    118                         plfOddOrEven.format(i));
    119                 assertEquals("Fully specified PluralFormat gave wrong results",
    120                         numberFormat.format(i) + ((i%2 == 1) ?  " is odd."
    121                                 :  " is even."),
    122                                 plfOddAndEven.format(i));
    123             }
    124 
    125             // ICU 4.8 does not check for duplicate keywords any more.
    126             PluralFormat pf = new PluralFormat(ULocale.ENGLISH, oddAndEven,
    127                     "odd{foo} odd{bar} other{foobar}");
    128             assertEquals("should use first occurrence of the 'odd' keyword", "foo", pf.format(1));
    129             pf.applyPattern("odd{foo} other{bar} other{foobar}");
    130             assertEquals("should use first occurrence of the 'other' keyword", "bar", pf.format(2));
    131             // This sees the first "other" before calling the PluralSelector which then selects "other".
    132             pf.applyPattern("other{foo} odd{bar} other{foobar}");
    133             assertEquals("should use first occurrence of the 'other' keyword", "foo", pf.format(2));
    134         }
    135         // omit other keyword.
    136         try {
    137             PluralFormat plFmt = new PluralFormat(oddAndEven);
    138             plFmt.applyPattern("odd{foo}");
    139             errln("Not defining plural case other should result in an " +
    140                     "exception but did not.");
    141         }catch (IllegalArgumentException e){}
    142 
    143         // ICU 4.8 does not check for unknown keywords any more.
    144         {
    145             PluralFormat pf = new PluralFormat(ULocale.ENGLISH, oddAndEven, "otto{foo} other{bar}");
    146             assertEquals("should ignore unknown keywords", "bar", pf.format(1));
    147         }
    148 
    149         // Test invalid keyword.
    150         try {
    151             PluralFormat plFmt = new PluralFormat(oddAndEven);
    152             plFmt.applyPattern("*odd{foo} other{bar}");
    153             errln("Defining a message for an invalid keyword should result in " +
    154                     "an exception but did not.");
    155         }catch (IllegalArgumentException e){}
    156 
    157         // Test invalid syntax
    158         //   -- comma between keyword{message} clauses
    159         //   -- space in keywords
    160         //   -- keyword{message1}{message2}
    161         try {
    162             PluralFormat plFmt = new PluralFormat(oddAndEven);
    163             plFmt.applyPattern("odd{foo},other{bar}");
    164             errln("Separating keyword{message} items with other characters " +
    165                     "than space should provoke an exception but did not.");
    166         }catch (IllegalArgumentException e){}
    167         try {
    168             PluralFormat plFmt = new PluralFormat(oddAndEven);
    169             plFmt.applyPattern("od d{foo} other{bar}");
    170             errln("Spaces inside keywords should provoke an exception but " +
    171                     "did not.");
    172         }catch (IllegalArgumentException e){}
    173         try {
    174             PluralFormat plFmt = new PluralFormat(oddAndEven);
    175             plFmt.applyPattern("odd{foo}{foobar}other{foo}");
    176             errln("Defining multiple messages after a keyword should provoke " +
    177                     "an exception but did not.");
    178         }catch (IllegalArgumentException e){}
    179 
    180         // Check that nested format is preserved.
    181         {
    182             PluralFormat plFmt = new PluralFormat(oddAndEven);
    183             plFmt.applyPattern("odd{The number {0, number, #.#0} is odd.}" +
    184                     "other{The number {0, number, #.#0} is even.}");
    185             for (int i = 1; i < 3; ++i) {
    186                 assertEquals("format did not preserve a nested format string.",
    187                         ((i % 2 == 1) ?
    188                                 "The number {0, number, #.#0} is odd."
    189                                 : "The number {0, number, #.#0} is even."),
    190                                 plFmt.format(i));
    191             }
    192 
    193         }
    194         // Check that a pound sign in curly braces is preserved.
    195         {
    196             PluralFormat plFmt = new PluralFormat(oddAndEven);
    197             plFmt.applyPattern("odd{The number {1,number,#} is odd.}" +
    198                     "other{The number {2,number,#} is even.}");
    199             for (int i = 1; i < 3; ++i) {
    200                 assertEquals("format did not preserve # inside curly braces.",
    201                         ((i % 2 == 1) ? "The number {1,number,#} is odd."
    202                                 : "The number {2,number,#} is even."),
    203                                 plFmt.format(i));
    204             }
    205 
    206         }
    207     }
    208 
    209 
    210     @Test
    211     public void TestSamples() {
    212         Map<ULocale,Set<ULocale>> same = new LinkedHashMap();
    213         for (ULocale locale : PluralRules.getAvailableULocales()) {
    214             ULocale otherLocale = PluralRules.getFunctionalEquivalent(locale, null);
    215             Set<ULocale> others = same.get(otherLocale);
    216             if (others == null) same.put(otherLocale, others = new LinkedHashSet());
    217             others.add(locale);
    218             continue;
    219         }
    220         for (ULocale locale0 : same.keySet()) {
    221             PluralRules rules = PluralRules.forLocale(locale0);
    222             String localeName = locale0.toString().length() == 0 ? "root" : locale0.toString();
    223             logln(localeName + "\t=\t" + same.get(locale0));
    224             logln(localeName + "\ttoString\t" + rules.toString());
    225             Set<String> keywords = rules.getKeywords();
    226             for (String keyword : keywords) {
    227                 Collection<Double> list = rules.getSamples(keyword);
    228                 if (list.size() == 0) {
    229                     // if there aren't any integer samples, get the decimal ones.
    230                     list = rules.getSamples(keyword, SampleType.DECIMAL);
    231                 }
    232 
    233                 if (list == null || list.size() == 0) {
    234                     errln("Empty list for " + localeName + " : " + keyword);
    235                 } else {
    236                     logln("\t" + localeName + " : " + keyword + " ; " + list);
    237                 }
    238             }
    239         }
    240     }
    241 
    242     @Test
    243     public void TestSetLocale() {
    244         // Create rules for testing.
    245         PluralRules oddAndEven = PluralRules.createRules("odd__: n mod 2 is 1");
    246 
    247         PluralFormat plFmt = new PluralFormat(oddAndEven);
    248         plFmt.applyPattern("odd__{odd} other{even}");
    249         plFmt.setLocale(ULocale.ENGLISH);
    250 
    251         // Check that pattern gets deleted.
    252         NumberFormat nrFmt = NumberFormat.getInstance(ULocale.ENGLISH);
    253         assertEquals("pattern was not resetted by setLocale() call.",
    254                 nrFmt.format(5),
    255                 plFmt.format(5));
    256 
    257         // Check that rules got updated.
    258         plFmt.applyPattern("odd__{odd} other{even}");
    259         assertEquals("SetLocale should reset rules but did not.", "even", plFmt.format(1));
    260 
    261         plFmt.applyPattern("one{one} other{not one}");
    262         for (int i = 0; i < 20; ++i) {
    263             assertEquals("Wrong ruleset loaded by setLocale()",
    264                     ((i==1) ? "one" : "not one"),
    265                     plFmt.format(i));
    266         }
    267     }
    268 
    269     @Test
    270     public void TestParse() {
    271         PluralFormat plFmt = new PluralFormat("other{test}");
    272         try {
    273             plFmt.parse("test", new ParsePosition(0));
    274             errln("parse() should throw an UnsupportedOperationException but " +
    275                     "did not");
    276         } catch (UnsupportedOperationException e) {
    277         }
    278 
    279         plFmt = new PluralFormat("other{test}");
    280         try {
    281             plFmt.parseObject("test", new ParsePosition(0));
    282             errln("parse() should throw an UnsupportedOperationException but " +
    283                     "did not");
    284         } catch (UnsupportedOperationException e) {
    285         }
    286     }
    287 
    288     @Test
    289     public void TestPattern() {
    290         Object[] args = { "acme", null };
    291 
    292         {
    293             // ICU 4.8 PluralFormat does not trim() its pattern any more.
    294             // None of the other *Format classes do.
    295             String pat = "  one {one ''widget} other {# widgets}  ";
    296             PluralFormat pf = new PluralFormat(pat);
    297             assertEquals("should not trim() the pattern", pat, pf.toPattern());
    298         }
    299 
    300         MessageFormat pfmt = new MessageFormat("The disk ''{0}'' contains {1, plural,  one {one ''''{1, number, #.0}'''' widget} other {# widgets}}.");
    301         logln("");
    302         for (int i = 0; i < 3; ++i) {
    303             args[1] = new Integer(i);
    304             logln(pfmt.format(args));
    305         }
    306         /* ICU 4.8 returns null instead of a choice/plural/select Format object
    307          * (because it does not create an object for any "complex" argument).
    308         PluralFormat pf = (PluralFormat)pfmt.getFormatsByArgumentIndex()[1];
    309         logln(pf.toPattern());
    310          */
    311         logln(pfmt.toPattern());
    312         MessageFormat pfmt2 = new MessageFormat(pfmt.toPattern());
    313         assertEquals("message formats are equal", pfmt, pfmt2);
    314     }
    315 
    316     @Test
    317     public void TestExtendedPluralFormat() {
    318         String[] targets = {
    319                 "There are no widgets.",
    320                 "There is one widget.",
    321                 "There is a bling widget and one other widget.",
    322                 "There is a bling widget and 2 other widgets.",
    323                 "There is a bling widget and 3 other widgets.",
    324                 "Widgets, five (5-1=4) there be.",
    325                 "There is a bling widget and 5 other widgets.",
    326                 "There is a bling widget and 6 other widgets.",
    327         };
    328         String pluralStyle =
    329                 "offset:1.0 "
    330                         + "=0 {There are no widgets.} "
    331                         + "=1.0 {There is one widget.} "
    332                         + "=5 {Widgets, five (5-1=#) there be.} "
    333                         + "one {There is a bling widget and one other widget.} "
    334                         + "other {There is a bling widget and # other widgets.}";
    335         PluralFormat pf = new PluralFormat(ULocale.ENGLISH, pluralStyle);
    336         MessageFormat mf = new MessageFormat("{0,plural," + pluralStyle + "}", ULocale.ENGLISH);
    337         Integer args[] = new Integer[1];
    338         for (int i = 0; i <= 7; ++i) {
    339             String result = pf.format(i);
    340             assertEquals("PluralFormat.format(value " + i + ")", targets[i], result);
    341             args[0] = i;
    342             result = mf.format(args);
    343             assertEquals("MessageFormat.format(value " + i + ")", targets[i], result);
    344         }
    345 
    346         // Try explicit values after keywords.
    347         pf.applyPattern("other{zz}other{yy}one{xx}one{ww}=1{vv}=1{uu}");
    348         assertEquals("should find first matching *explicit* value", "vv", pf.format(1));
    349     }
    350 
    351     @Test
    352     public void TestExtendedPluralFormatParsing() {
    353         String[] failures = {
    354                 "offset:1..0 =0 {Foo}",
    355                 "offset:1.0 {Foo}",
    356                 "=0= {Foo}",
    357                 "=0 {Foo} =0.0 {Bar}",
    358                 " = {Foo}",
    359         };
    360         for (String fmt : failures) {
    361             try {
    362                 new PluralFormat(fmt);
    363                 fail("expected exception when parsing '" + fmt + "'");
    364             } catch (IllegalArgumentException e) {
    365                 // ok
    366             }
    367         }
    368     }
    369 
    370     @Test
    371     public void TestOrdinalFormat() {
    372         String pattern = "one{#st file}two{#nd file}few{#rd file}other{#th file}";
    373         PluralFormat pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL, pattern);
    374         assertEquals("PluralFormat.format(321)", "321st file", pf.format(321));
    375         assertEquals("PluralFormat.format(22)", "22nd file", pf.format(22));
    376         assertEquals("PluralFormat.format(3)", "3rd file", pf.format(3));
    377 
    378         // Code coverage: Use the other new-for-PluralType constructor as well.
    379         pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL);
    380         pf.applyPattern(pattern);
    381         assertEquals("PluralFormat.format(456)", "456th file", pf.format(456));
    382         assertEquals("PluralFormat.format(111)", "111th file", pf.format(111));
    383 
    384         // Code coverage: Use Locale not ULocale.
    385         pf = new PluralFormat(Locale.ENGLISH, PluralType.ORDINAL);
    386         pf.applyPattern(pattern);
    387         assertEquals("PluralFormat.format(456)", "456th file", pf.format(456));
    388         assertEquals("PluralFormat.format(111)", "111th file", pf.format(111));
    389     }
    390 
    391     @Test
    392     public void TestDecimals() {
    393         // Simple number replacement.
    394         PluralFormat pf = new PluralFormat(ULocale.ENGLISH, "one{one meter}other{# meters}");
    395         assertEquals("simple format(1)", "one meter", pf.format(1));
    396         assertEquals("simple format(1.5)", "1.5 meters", pf.format(1.5));
    397         PluralFormat pf2 = new PluralFormat(ULocale.ENGLISH,
    398                 "offset:1 one{another meter}other{another # meters}");
    399         pf2.setNumberFormat(new DecimalFormat("0.0", new DecimalFormatSymbols(ULocale.ENGLISH)));
    400         assertEquals("offset-decimals format(1)", "another 0.0 meters", pf2.format(1));
    401         assertEquals("offset-decimals format(2)", "another 1.0 meters", pf2.format(2));
    402         assertEquals("offset-decimals format(2.5)", "another 1.5 meters", pf2.format(2.5));
    403     }
    404 
    405     @Test
    406     public void TestNegative() {
    407         PluralFormat pluralFormat = new PluralFormat(ULocale.ENGLISH, "one{# foot}other{# feet}");
    408         String actual = pluralFormat.format(-3);
    409         assertEquals(pluralFormat.toString(), "-3 feet", actual);
    410     }
    411 }
    412