Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.util;
     18 
     19 import java.text.BreakIterator;
     20 import java.text.Collator;
     21 import java.text.DateFormat;
     22 import java.text.DateFormatSymbols;
     23 import java.text.NumberFormat;
     24 import java.util.Calendar;
     25 import java.util.IllformedLocaleException;
     26 import java.util.Locale;
     27 import java.util.MissingResourceException;
     28 
     29 public class LocaleTest extends junit.framework.TestCase {
     30     // http://b/2611311; if there's no display language/country/variant, use the raw codes.
     31     public void test_getDisplayName_invalid() throws Exception {
     32         Locale invalid = new Locale("AaBbCc", "DdEeFf", "GgHhIi");
     33 
     34         assertEquals("aabbcc", invalid.getLanguage());
     35         assertEquals("DDEEFF", invalid.getCountry());
     36         assertEquals("GgHhIi", invalid.getVariant());
     37 
     38         // Android using icu4c < 49.2 returned empty strings for display language, country,
     39         // and variant, but a display name made up of the raw strings.
     40         // Newer releases return slightly different results, but no less unreasonable.
     41         assertEquals("aabbcc", invalid.getDisplayLanguage());
     42         assertEquals("DDEEFF", invalid.getDisplayCountry());
     43         assertEquals("GGHHII", invalid.getDisplayVariant());
     44         assertEquals("aabbcc (DDEEFF,GGHHII)", invalid.getDisplayName());
     45     }
     46 
     47     public void test_getDisplayName_emptyCodes() {
     48         Locale emptyLanguage = new Locale("", "DdeEFf");
     49         assertEquals("", emptyLanguage.getDisplayLanguage());
     50 
     51         Locale emptyCountry = new Locale("AaBbCc", "");
     52         assertEquals("", emptyCountry.getDisplayCountry());
     53 
     54         Locale emptyCountryAndLanguage = new Locale("", "", "Farl");
     55         assertEquals("", emptyCountryAndLanguage.getDisplayLanguage());
     56         assertEquals("", emptyCountryAndLanguage.getDisplayCountry());
     57         assertEquals("Farl", emptyCountryAndLanguage.getDisplayVariant());
     58     }
     59 
     60     // http://b/2611311; if there's no display language/country/variant, use the raw codes.
     61     public void test_getDisplayName_unknown() throws Exception {
     62         Locale unknown = new Locale("xx", "YY", "Traditional");
     63         assertEquals("xx", unknown.getLanguage());
     64         assertEquals("YY", unknown.getCountry());
     65         assertEquals("Traditional", unknown.getVariant());
     66 
     67         assertEquals("xx", unknown.getDisplayLanguage());
     68         assertEquals("YY", unknown.getDisplayCountry());
     69         assertEquals("Traditional", unknown.getDisplayVariant());
     70         assertEquals("xx (YY,Traditional)", unknown.getDisplayName());
     71     }
     72 
     73     public void test_getDisplayName_easy() throws Exception {
     74         assertEquals("English", Locale.ENGLISH.getDisplayLanguage(Locale.ENGLISH));
     75         assertEquals("German", Locale.GERMAN.getDisplayLanguage(Locale.ENGLISH));
     76         assertEquals("Englisch", Locale.ENGLISH.getDisplayLanguage(Locale.GERMAN));
     77         assertEquals("Deutsch", Locale.GERMAN.getDisplayLanguage(Locale.GERMAN));
     78     }
     79 
     80     // https://b/issue?id=13790528
     81     public void test_getDisplayName_withScriptsAndVariants() throws Exception {
     82         // Script + Country.
     83         assertEquals("Chinese (Traditional Han,China)",
     84                 Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US));
     85         // Script + Variant.
     86         assertEquals("Chinese (Traditional Han,VARIANT)",
     87                 Locale.forLanguageTag("zh-Hant-VARIANT").getDisplayName(Locale.US));
     88         // Country + Variant.
     89         assertEquals("Chinese (China,VARIANT)",
     90                 Locale.forLanguageTag("zh-CN-VARIANT").getDisplayName(Locale.US));
     91         // Script + Country + variant.
     92         assertEquals("Chinese (Traditional Han,China,VARIANT)",
     93                 Locale.forLanguageTag("zh-Hant-CN-VARIANT").getDisplayName(Locale.US));
     94     }
     95 
     96     public void test_getDisplayCountry_8870289() throws Exception {
     97         assertEquals("Hong Kong", new Locale("", "HK").getDisplayCountry(Locale.US));
     98         assertEquals("Macau", new Locale("", "MO").getDisplayCountry(Locale.US));
     99         assertEquals("Palestine", new Locale("", "PS").getDisplayCountry(Locale.US));
    100 
    101         assertEquals("Cocos (Keeling) Islands", new Locale("", "CC").getDisplayCountry(Locale.US));
    102         assertEquals("Congo (DRC)", new Locale("", "CD").getDisplayCountry(Locale.US));
    103         assertEquals("Congo (Republic)", new Locale("", "CG").getDisplayCountry(Locale.US));
    104         assertEquals("Falkland Islands (Islas Malvinas)", new Locale("", "FK").getDisplayCountry(Locale.US));
    105         assertEquals("Macedonia (FYROM)", new Locale("", "MK").getDisplayCountry(Locale.US));
    106         assertEquals("Myanmar (Burma)", new Locale("", "MM").getDisplayCountry(Locale.US));
    107         assertEquals("Taiwan", new Locale("", "TW").getDisplayCountry(Locale.US));
    108     }
    109 
    110     public void test_tl_and_fil() throws Exception {
    111         // In jb-mr1, we had a last-minute hack to always return "Filipino" because
    112         // icu4c 4.8 didn't have any localizations for fil. (http://b/7291355).
    113         //
    114         // After the icu4c 4.9 upgrade, we could localize "fil" correctly, though we
    115         // needed another hack to supply "fil" instead of "tl" to icu4c. (http://b/8023288).
    116         //
    117         // These hacks have now been reverted, so "tl" really does represent
    118         // tagalog and not filipino.
    119         Locale tl = new Locale("tl");
    120         Locale tl_PH = new Locale("tl", "PH");
    121         assertEquals("Tagalog", tl.getDisplayLanguage(Locale.ENGLISH));
    122         assertEquals("Tagalog", tl_PH.getDisplayLanguage(Locale.ENGLISH));
    123         assertEquals("tl", tl.getDisplayLanguage(tl));
    124         assertEquals("tl", tl_PH.getDisplayLanguage(tl_PH));
    125 
    126         Locale es_MX = new Locale("es", "MX");
    127         assertEquals("tagalo", tl.getDisplayLanguage(es_MX));
    128         assertEquals("tagalo", tl_PH.getDisplayLanguage(es_MX));
    129 
    130         // Assert that we can deal with "fil" correctly, since we've switched
    131         // to using "fil" for Filipino, and not "tl". (http://b/15873165).
    132         Locale fil = new Locale("fil");
    133         Locale fil_PH = new Locale("fil", "PH");
    134         assertEquals("Filipino", fil.getDisplayLanguage(Locale.ENGLISH));
    135         assertEquals("Filipino", fil_PH.getDisplayLanguage(Locale.ENGLISH));
    136         assertEquals("Filipino", fil.getDisplayLanguage(fil));
    137         assertEquals("Filipino", fil_PH.getDisplayLanguage(fil_PH));
    138 
    139         assertEquals("filipino", fil.getDisplayLanguage(es_MX));
    140         assertEquals("filipino", fil_PH.getDisplayLanguage(es_MX));
    141     }
    142 
    143     // http://b/3452611; Locale.getDisplayLanguage fails for the obsolete language codes.
    144     public void test_getDisplayName_obsolete() throws Exception {
    145         // he (new) -> iw (obsolete)
    146         assertObsolete("he", "iw", "");
    147         // id (new) -> in (obsolete)
    148         assertObsolete("id", "in", "Bahasa Indonesia");
    149     }
    150 
    151     private static void assertObsolete(String newCode, String oldCode, String displayName) {
    152         // Either code should get you the same locale.
    153         Locale newLocale = new Locale(newCode);
    154         Locale oldLocale = new Locale(oldCode);
    155         assertEquals(newLocale, oldLocale);
    156 
    157         // No matter what code you used to create the locale, you should get the old code back.
    158         assertEquals(oldCode, newLocale.getLanguage());
    159         assertEquals(oldCode, oldLocale.getLanguage());
    160 
    161         // Check we get the right display name.
    162         assertEquals(displayName, newLocale.getDisplayLanguage(newLocale));
    163         assertEquals(displayName, oldLocale.getDisplayLanguage(newLocale));
    164         assertEquals(displayName, newLocale.getDisplayLanguage(oldLocale));
    165         assertEquals(displayName, oldLocale.getDisplayLanguage(oldLocale));
    166 
    167         // Check that none of the 'getAvailableLocales' methods are accidentally returning two
    168         // equal locales (because to ICU they're different, but we mangle one into the other).
    169         assertOnce(newLocale, BreakIterator.getAvailableLocales());
    170         assertOnce(newLocale, Calendar.getAvailableLocales());
    171         assertOnce(newLocale, Collator.getAvailableLocales());
    172         assertOnce(newLocale, DateFormat.getAvailableLocales());
    173         assertOnce(newLocale, DateFormatSymbols.getAvailableLocales());
    174         assertOnce(newLocale, NumberFormat.getAvailableLocales());
    175         assertOnce(newLocale, Locale.getAvailableLocales());
    176     }
    177 
    178     private static void assertOnce(Locale element, Locale[] array) {
    179         int count = 0;
    180         for (Locale l : array) {
    181             if (l.equals(element)) {
    182                 ++count;
    183             }
    184         }
    185         assertEquals(1, count);
    186     }
    187 
    188     public void test_getISO3Country() {
    189         // Empty country code.
    190         assertEquals("", new Locale("en", "").getISO3Country());
    191 
    192         // Invalid country code.
    193         try {
    194             assertEquals("", new Locale("en", "XX").getISO3Country());
    195             fail();
    196         } catch (MissingResourceException expected) {
    197             assertEquals("FormatData_en_XX", expected.getClassName());
    198             assertEquals("ShortCountry", expected.getKey());
    199         }
    200 
    201         // Valid country code.
    202         assertEquals("CAN", new Locale("", "CA").getISO3Country());
    203         assertEquals("CAN", new Locale("en", "CA").getISO3Country());
    204         assertEquals("CAN", new Locale("xx", "CA").getISO3Country());
    205 
    206         // 3 letter country codes.
    207         assertEquals("CAN", new Locale("en", "CAN").getISO3Country());
    208         assertEquals("CAN", new Locale("frankenderp", "CAN").getISO3Country());
    209     }
    210 
    211     public void test_getISO3Language() {
    212         // Empty language code.
    213         assertEquals("", new Locale("", "US").getISO3Language());
    214 
    215         // Invalid language code.
    216         try {
    217             assertEquals("", new Locale("xx", "US").getISO3Language());
    218             fail();
    219         } catch (MissingResourceException expected) {
    220             assertEquals("FormatData_xx_US", expected.getClassName());
    221             assertEquals("ShortLanguage", expected.getKey());
    222         }
    223 
    224         // Valid language code.
    225         assertEquals("eng", new Locale("en", "").getISO3Language());
    226         assertEquals("eng", new Locale("en", "CA").getISO3Language());
    227         assertEquals("eng", new Locale("en", "XX").getISO3Language());
    228 
    229         // 3 letter language code.
    230         assertEquals("eng", new Locale("eng", "USA").getISO3Language());
    231         assertEquals("eng", new Locale("eng", "US").getISO3Language());
    232     }
    233 
    234     public void test_Builder_setLanguage() {
    235         Locale.Builder b = new Locale.Builder();
    236 
    237         // Should normalize to lower case.
    238         b.setLanguage("EN");
    239         assertEquals("en", b.build().getLanguage());
    240 
    241         b = new Locale.Builder();
    242 
    243         // Too short.
    244         try {
    245             b.setLanguage("e");
    246             fail();
    247         } catch (IllformedLocaleException expected) {
    248         }
    249 
    250         // Too long
    251         try {
    252             b.setLanguage("engl");
    253             fail();
    254         } catch (IllformedLocaleException expected) {
    255         }
    256 
    257         // Contains non ASCII characters
    258         try {
    259             b.setLanguage("");
    260             fail();
    261         } catch (IllformedLocaleException expected) {
    262         }
    263 
    264         // Null or empty languages must clear state.
    265         b = new Locale.Builder();
    266         b.setLanguage("en");
    267         b.setLanguage(null);
    268         assertEquals("", b.build().getLanguage());
    269 
    270         b = new Locale.Builder();
    271         b.setLanguage("en");
    272         b.setLanguage("");
    273         assertEquals("", b.build().getLanguage());
    274     }
    275 
    276     public void test_Builder_setRegion() {
    277         Locale.Builder b = new Locale.Builder();
    278 
    279         // Should normalize to upper case.
    280         b.setRegion("us");
    281         assertEquals("US", b.build().getCountry());
    282 
    283         b = new Locale.Builder();
    284 
    285         // Too short.
    286         try {
    287             b.setRegion("e");
    288             fail();
    289         } catch (IllformedLocaleException expected) {
    290         }
    291 
    292         // Too long
    293         try {
    294             b.setRegion("USA");
    295             fail();
    296         } catch (IllformedLocaleException expected) {
    297         }
    298 
    299         // Contains non ASCII characters
    300         try {
    301             b.setLanguage("");
    302             fail();
    303         } catch (IllformedLocaleException expected) {
    304         }
    305 
    306         // Null or empty regions must clear state.
    307         b = new Locale.Builder();
    308         b.setRegion("US");
    309         b.setRegion(null);
    310         assertEquals("", b.build().getCountry());
    311 
    312         b = new Locale.Builder();
    313         b.setRegion("US");
    314         b.setRegion("");
    315         assertEquals("", b.build().getCountry());
    316     }
    317 
    318     public void test_Builder_setVariant() {
    319         Locale.Builder b = new Locale.Builder();
    320 
    321         // Should normalize "_" to "-"
    322         b = new Locale.Builder();
    323         b.setVariant("vArIaNt-VaRiAnT-VARIANT");
    324         assertEquals("vArIaNt_VaRiAnT_VARIANT", b.build().getVariant());
    325 
    326         b = new Locale.Builder();
    327         // Too short
    328         try {
    329             b.setVariant("shor");
    330             fail();
    331         } catch (IllformedLocaleException expected) {
    332         }
    333 
    334         // Too long
    335         try {
    336             b.setVariant("waytoolong");
    337             fail();
    338         } catch (IllformedLocaleException expected) {
    339         }
    340 
    341         try {
    342             b.setVariant("foooo-foooo-fo");
    343             fail();
    344         } catch (IllformedLocaleException expected) {
    345         }
    346 
    347         // Special case. Variants of length 4 are allowed when the first
    348         // character is a digit.
    349         b.setVariant("0ABC");
    350         assertEquals("0ABC", b.build().getVariant());
    351 
    352         b = new Locale.Builder();
    353         b.setVariant("variant");
    354         b.setVariant(null);
    355         assertEquals("", b.build().getVariant());
    356 
    357         b = new Locale.Builder();
    358         b.setVariant("variant");
    359         b.setVariant("");
    360         assertEquals("", b.build().getVariant());
    361     }
    362 
    363     public void test_Builder_setLocale() {
    364         // Default case.
    365         Locale.Builder b = new Locale.Builder();
    366         b.setLocale(Locale.US);
    367         assertEquals("en", b.build().getLanguage());
    368         assertEquals("US", b.build().getCountry());
    369 
    370         // Should throw when locale is malformed.
    371         // - Bad language
    372         Locale bad = new Locale("e", "US");
    373         b = new Locale.Builder();
    374         try {
    375             b.setLocale(bad);
    376             fail();
    377         } catch (IllformedLocaleException expected) {
    378         }
    379         // - Bad country
    380         bad = new Locale("en", "USA");
    381         try {
    382             b.setLocale(bad);
    383             fail();
    384         } catch (IllformedLocaleException expected) {
    385         }
    386 
    387         // - Bad variant
    388         bad = new Locale("en", "US", "c");
    389         try {
    390             b.setLocale(bad);
    391             fail();
    392         } catch (IllformedLocaleException expected) {
    393         }
    394 
    395         // Test values are normalized as they should be
    396         b = new Locale.Builder();
    397         Locale good = new Locale("EN", "us", "variant-VARIANT");
    398         b.setLocale(good);
    399         Locale l = b.build();
    400         assertEquals("en", l.getLanguage());
    401         assertEquals("US", l.getCountry());
    402         assertEquals("variant_VARIANT", l.getVariant());
    403 
    404         // Test that none of the existing fields are messed with
    405         // if the locale update fails.
    406         b = new Locale.Builder();
    407         b.setLanguage("fr").setRegion("FR");
    408 
    409         try {
    410             b.setLocale(bad);
    411             fail();
    412         } catch (IllformedLocaleException expected) {
    413         }
    414 
    415         l = b.build();
    416         assertEquals("fr", l.getLanguage());
    417         assertEquals("FR", l.getCountry());
    418     }
    419 
    420     public void test_Builder_setScript() {
    421         Locale.Builder b = new Locale.Builder();
    422 
    423         // Should normalize variants to lower case.
    424         b.setScript("lAtN");
    425         assertEquals("Latn", b.build().getScript());
    426 
    427         b = new Locale.Builder();
    428         // Too short
    429         try {
    430             b.setScript("lat");
    431             fail();
    432         } catch (IllformedLocaleException expected) {
    433         }
    434 
    435         // Too long
    436         try {
    437             b.setScript("latin");
    438             fail();
    439         } catch (IllformedLocaleException expected) {
    440         }
    441 
    442         b = new Locale.Builder();
    443         b.setScript("Latn");
    444         b.setScript(null);
    445         assertEquals("", b.build().getScript());
    446 
    447         b = new Locale.Builder();
    448         b.setScript("Latn");
    449         b.setScript("");
    450         assertEquals("", b.build().getScript());
    451     }
    452 
    453     public void test_Builder_clear() {
    454         Locale.Builder b = new Locale.Builder();
    455         b.setLanguage("en").setScript("Latn").setRegion("US")
    456                 .setVariant("POSIX").setExtension('g', "foo")
    457                 .setUnicodeLocaleKeyword("fo", "baar")
    458                 .addUnicodeLocaleAttribute("baaaaz");
    459 
    460         Locale l = b.clear().build();
    461         assertEquals("", l.getLanguage());
    462         assertEquals("", l.getCountry());
    463         assertEquals("", l.getVariant());
    464         assertEquals("", l.getScript());
    465         assertTrue(l.getExtensionKeys().isEmpty());
    466     }
    467 
    468     public void test_Builder_setExtension() {
    469         Locale.Builder b = new Locale.Builder();
    470         b.setExtension('g', "FO_ba-BR_bg");
    471 
    472         Locale l = b.build();
    473         assertEquals("fo-ba-br-bg", l.getExtension('g'));
    474 
    475         b = new Locale.Builder();
    476 
    477         // Too short
    478         try {
    479             b.setExtension('g', "fo-ba-br-x");
    480             fail();
    481         } catch (IllformedLocaleException expected) {
    482         }
    483 
    484         // Too long
    485         try {
    486             b.setExtension('g', "fo-ba-br-extension");
    487             fail();
    488         } catch (IllformedLocaleException expected) {
    489         }
    490 
    491         // Special case, the private use extension allows single char subtags.
    492         b.setExtension(Locale.PRIVATE_USE_EXTENSION, "fo-ba-br-m");
    493         l = b.build();
    494         assertEquals("fo-ba-br-m", l.getExtension('x'));
    495 
    496         // Special case, the unicode locale extension must be parsed into
    497         // its individual components. The correctness of the parse is tested
    498         // in test_parseUnicodeExtension.
    499         b.setExtension(Locale.UNICODE_LOCALE_EXTENSION, "foooo_BaaaR-BA_Baz-bI_BIZ");
    500         l = b.build();
    501         // Note that attributes and keywords are sorted alphabetically.
    502         assertEquals("baaar-foooo-ba-baz-bi-biz", l.getExtension('u'));
    503 
    504         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
    505         assertTrue(l.getUnicodeLocaleAttributes().contains("baaar"));
    506         assertEquals("baz", l.getUnicodeLocaleType("ba"));
    507         assertEquals("biz", l.getUnicodeLocaleType("bi"));
    508     }
    509 
    510     public void test_Builder_clearExtensions() {
    511         Locale.Builder b = new Locale.Builder();
    512         b.setExtension('g', "FO_ba-BR_bg");
    513         b.setExtension(Locale.PRIVATE_USE_EXTENSION, "fo-ba-br-m");
    514         b.clearExtensions();
    515 
    516         assertTrue(b.build().getExtensionKeys().isEmpty());
    517     }
    518 
    519     private static Locale fromLanguageTag(String languageTag, boolean useBuilder) {
    520         if (useBuilder) {
    521             return (new Locale.Builder().setLanguageTag(languageTag).build());
    522         } else {
    523             return Locale.forLanguageTag(languageTag);
    524         }
    525     }
    526 
    527     private void test_setLanguageTag_wellFormedsingleSubtag(boolean useBuilder) {
    528         Locale l = fromLanguageTag("en", useBuilder);
    529         assertEquals("en", l.getLanguage());
    530 
    531         l = fromLanguageTag("eng", useBuilder);
    532         assertEquals("eng", l.getLanguage());
    533     }
    534 
    535     private void test_setLanguageTag_twoWellFormedSubtags(boolean useBuilder) {
    536         Locale l =  fromLanguageTag("en-US", useBuilder);
    537         assertEquals("en", l.getLanguage());
    538         assertEquals("US", l.getCountry());
    539 
    540         l =  fromLanguageTag("eng-419", useBuilder);
    541         assertEquals("eng", l.getLanguage());
    542         assertEquals("419", l.getCountry());
    543 
    544         // Script tags shouldn't be mis-recognized as regions.
    545         l =  fromLanguageTag("en-Latn", useBuilder);
    546         assertEquals("en", l.getLanguage());
    547         assertEquals("", l.getCountry());
    548         assertEquals("Latn", l.getScript());
    549 
    550         // Neither should variant tags.
    551         l =  fromLanguageTag("en-POSIX", useBuilder);
    552         assertEquals("en", l.getLanguage());
    553         assertEquals("", l.getCountry());
    554         assertEquals("", l.getScript());
    555         assertEquals("POSIX", l.getVariant());
    556     }
    557 
    558     public void test_Builder_setLanguageTag_malformedTags() {
    559         try {
    560             fromLanguageTag("a", true);
    561             fail();
    562         } catch (IllformedLocaleException ifle) {
    563         }
    564 
    565         // Three subtags
    566         // lang-region-illformedvariant
    567         try {
    568             fromLanguageTag("en-US-BA", true);
    569             fail();
    570         } catch (IllformedLocaleException expected) {
    571         }
    572 
    573         // lang-variant-illformedvariant
    574         try {
    575             fromLanguageTag("en-FOOOO-BA", true);
    576             fail();
    577         } catch (IllformedLocaleException expected) {
    578         }
    579 
    580         // Four or more sub tags
    581         try {
    582             fromLanguageTag("en-US-POSIX-P2", true);
    583             fail();
    584         } catch (IllformedLocaleException expected) {
    585         }
    586 
    587         try {
    588             fromLanguageTag("en-Latn-US-P2", true);
    589             fail();
    590         } catch (IllformedLocaleException expected) {
    591         }
    592 
    593         // Extensions
    594         // Ill-formed empty extension.
    595         try {
    596             fromLanguageTag("en-f-f", true);
    597             fail();
    598         } catch (IllformedLocaleException expected) {
    599         }
    600 
    601         // Ill-formed empty extension.
    602         try {
    603             fromLanguageTag("en-f", true);
    604             fail();
    605         } catch (IllformedLocaleException expected) {
    606         }
    607 
    608         // Two extension keys in a row (i.e, another case of an ill-formed
    609         // empty exception).
    610         try {
    611             fromLanguageTag("en-f-g-fo-baar", true);
    612             fail();
    613         } catch (IllformedLocaleException expected) {
    614         }
    615 
    616         // Dangling empty key after a well formed extension.
    617         try {
    618             fromLanguageTag("en-f-fo-baar-g", true);
    619             fail();
    620         } catch (IllformedLocaleException expected) {
    621         }
    622 
    623         // Ill-formed extension with long subtag.
    624         try {
    625             fromLanguageTag("en-f-fooobaaaz", true);
    626             fail();
    627         } catch (IllformedLocaleException expected) {
    628         }
    629     }
    630 
    631     private void test_setLanguageTag_threeWellFormedSubtags(boolean useBuilder) {
    632         // lang-region-variant
    633         Locale l = fromLanguageTag("en-US-FOOOO", useBuilder);
    634         assertEquals("en", l.getLanguage());
    635         assertEquals("US", l.getCountry());
    636         assertEquals("", l.getScript());
    637         assertEquals("FOOOO", l.getVariant());
    638 
    639         // lang-script-variant
    640         l = fromLanguageTag("en-Latn-FOOOO", useBuilder);
    641         assertEquals("en", l.getLanguage());
    642         assertEquals("", l.getCountry());
    643         assertEquals("Latn", l.getScript());
    644         assertEquals("FOOOO", l.getVariant());
    645 
    646         // lang-script-region
    647         l = fromLanguageTag("en-Latn-US", useBuilder);
    648         assertEquals("en", l.getLanguage());
    649         assertEquals("US", l.getCountry());
    650         assertEquals("Latn", l.getScript());
    651         assertEquals("", l.getVariant());
    652 
    653         // lang-variant-variant
    654         l = fromLanguageTag("en-FOOOO-BAAAR", useBuilder);
    655         assertEquals("en", l.getLanguage());
    656         assertEquals("", l.getCountry());
    657         assertEquals("", l.getScript());
    658         assertEquals("FOOOO_BAAAR", l.getVariant());
    659     }
    660 
    661     private void test_setLanguageTag_fourOrMoreWellFormedSubtags(boolean useBuilder) {
    662         // lang-script-region-variant.
    663         Locale l = fromLanguageTag("en-Latn-US-foooo", useBuilder);
    664         assertEquals("en", l.getLanguage());
    665         assertEquals("Latn", l.getScript());
    666         assertEquals("US", l.getCountry());
    667         assertEquals("foooo", l.getVariant());
    668 
    669         // Variant with multiple subtags.
    670         l = fromLanguageTag("en-Latn-US-foooo-gfffh", useBuilder);
    671         assertEquals("en", l.getLanguage());
    672         assertEquals("Latn", l.getScript());
    673         assertEquals("US", l.getCountry());
    674         assertEquals("foooo_gfffh", l.getVariant());
    675 
    676         // Variant with 3 subtags. POSIX shouldn't be recognized
    677         // as a region or a script.
    678         l = fromLanguageTag("en-POSIX-P2003-P2004", useBuilder);
    679         assertEquals("en", l.getLanguage());
    680         assertEquals("", l.getScript());
    681         assertEquals("", l.getCountry());
    682         assertEquals("POSIX_P2003_P2004", l.getVariant());
    683 
    684         // lang-script-variant-variant.
    685         l = fromLanguageTag("en-Latn-POSIX-P2003", useBuilder);
    686         assertEquals("en", l.getLanguage());
    687         assertEquals("Latn", l.getScript());
    688         assertEquals("", l.getCountry());
    689         assertEquals("POSIX_P2003", l.getVariant());
    690 
    691         // lang-region-variant-variant
    692         l = fromLanguageTag("en-US-POSIX-P2003", useBuilder);
    693         assertEquals("en", l.getLanguage());
    694         assertEquals("", l.getScript());
    695         assertEquals("US", l.getCountry());
    696         assertEquals("POSIX_P2003", l.getVariant());
    697     }
    698 
    699     private void test_setLanguageTag_withWellFormedExtensions(boolean useBuilder) {
    700         Locale l = fromLanguageTag("en-Latn-GB-foooo-g-fo-bar-baaz", useBuilder);
    701         assertEquals("en", l.getLanguage());
    702         assertEquals("Latn", l.getScript());
    703         assertEquals("GB", l.getCountry());
    704         assertEquals("foooo", l.getVariant());
    705         assertEquals("fo-bar-baaz", l.getExtension('g'));
    706 
    707         // Multiple extensions
    708         l = fromLanguageTag("en-Latn-US-foooo-g-fo-bar-h-go-gaz", useBuilder);
    709         assertEquals("en", l.getLanguage());
    710         assertEquals("Latn", l.getScript());
    711         assertEquals("US", l.getCountry());
    712         assertEquals("foooo", l.getVariant());
    713         assertEquals("fo-bar", l.getExtension('g'));
    714         assertEquals("go-gaz", l.getExtension('h'));
    715 
    716         // Unicode locale extension.
    717         l = fromLanguageTag("en-Latn-US-foooo-u-koooo-fo-bar", useBuilder);
    718         assertEquals("en", l.getLanguage());
    719         assertEquals("Latn", l.getScript());
    720         assertEquals("US", l.getCountry());
    721         assertEquals("koooo-fo-bar", l.getExtension('u'));
    722         assertTrue(l.getUnicodeLocaleAttributes().contains("koooo"));
    723         assertEquals("bar", l.getUnicodeLocaleType("fo"));
    724 
    725         // Extensions without variants
    726         l = fromLanguageTag("en-Latn-US-f-fo", useBuilder);
    727         assertEquals("en", l.getLanguage());
    728         assertEquals("Latn", l.getScript());
    729         assertEquals("US", l.getCountry());
    730         assertEquals("fo", l.getExtension('f'));
    731 
    732         l = fromLanguageTag("en-Latn-f-fo", useBuilder);
    733         assertEquals("en", l.getLanguage());
    734         assertEquals("Latn", l.getScript());
    735         assertEquals("fo", l.getExtension('f'));
    736 
    737         l = fromLanguageTag("en-f-fo", useBuilder);
    738         assertEquals("en", l.getLanguage());
    739         assertEquals("", l.getScript());
    740         assertEquals("", l.getCountry());
    741         assertEquals("fo", l.getExtension('f'));
    742 
    743         l = fromLanguageTag("en-f-fo-x-a-b-c-d-e-fo", useBuilder);
    744         assertEquals("en", l.getLanguage());
    745         assertEquals("", l.getScript());
    746         assertEquals("", l.getCountry());
    747         assertEquals("fo", l.getExtension('f'));
    748         assertEquals("a-b-c-d-e-fo", l.getExtension('x'));
    749     }
    750 
    751     public void test_forLanguageTag() {
    752         test_setLanguageTag_wellFormedsingleSubtag(false);
    753         test_setLanguageTag_twoWellFormedSubtags(false);
    754         test_setLanguageTag_threeWellFormedSubtags(false);
    755         test_setLanguageTag_fourOrMoreWellFormedSubtags(false);
    756         test_setLanguageTag_withWellFormedExtensions(false);
    757     }
    758 
    759     public void test_Builder_setLanguageTag() {
    760         test_setLanguageTag_wellFormedsingleSubtag(true);
    761         test_setLanguageTag_twoWellFormedSubtags(true);
    762         test_setLanguageTag_threeWellFormedSubtags(true);
    763         test_setLanguageTag_fourOrMoreWellFormedSubtags(true);
    764         test_setLanguageTag_withWellFormedExtensions(true);
    765     }
    766 
    767     public void test_getDisplayScript() {
    768         Locale.Builder b = new Locale.Builder();
    769         b.setLanguage("en").setRegion("US").setScript("Latn");
    770 
    771         Locale l = b.build();
    772 
    773         // getDisplayScript() test relies on the default locale. We set it here to avoid test
    774         // failures if the test device is set to a non-English locale.
    775         Locale.setDefault(Locale.US);
    776         assertEquals("Latin", l.getDisplayScript());
    777 
    778         assertEquals("Lateinisch", l.getDisplayScript(Locale.GERMAN));
    779         // Fallback for navajo, a language for which we don't have data.
    780         assertEquals("Latin", l.getDisplayScript(new Locale("nv", "US")));
    781 
    782         b= new Locale.Builder();
    783         b.setLanguage("en").setRegion("US").setScript("Fooo");
    784 
    785         // Will be equivalent to getScriptCode for scripts that aren't
    786         // registered with ISO-15429 (but are otherwise well formed).
    787         l = b.build();
    788         assertEquals("Fooo", l.getDisplayScript());
    789     }
    790 
    791     public void test_setLanguageTag_malformedTags() {
    792         Locale l = fromLanguageTag("a", false);
    793         assertEquals("und", l.getLanguage());
    794         assertEquals("", l.getCountry());
    795         assertEquals("", l.getVariant());
    796         assertEquals("", l.getScript());
    797 
    798         l = fromLanguageTag("en-US-BA", false);
    799         assertEquals("en", l.getLanguage());
    800         assertEquals("US", l.getCountry());
    801         assertEquals("", l.getVariant());
    802         assertEquals("", l.getScript());
    803 
    804         l = fromLanguageTag("en-FOOOO-BA", false);
    805         assertEquals("en", l.getLanguage());
    806         assertEquals("", l.getCountry());
    807         assertEquals("FOOOO", l.getVariant());
    808         assertEquals("", l.getScript());
    809 
    810         l = fromLanguageTag("en-US-POSIX-P2", false);
    811         assertEquals("en", l.getLanguage());
    812         assertEquals("US", l.getCountry());
    813         assertEquals("POSIX", l.getVariant());
    814         assertEquals("", l.getScript());
    815 
    816         l = fromLanguageTag("en-Latn-US-P2", false);
    817         assertEquals("en", l.getLanguage());
    818         assertEquals("US", l.getCountry());
    819         assertEquals("Latn", l.getScript());
    820 
    821         l = fromLanguageTag("en-f-f", false);
    822         assertEquals("en", l.getLanguage());
    823         assertEquals("", l.getCountry());
    824         assertEquals("", l.getVariant());
    825         assertEquals("", l.getScript());
    826 
    827         l = fromLanguageTag("en-f", false);
    828         assertEquals("en", l.getLanguage());
    829         assertEquals("", l.getCountry());
    830         assertEquals("", l.getVariant());
    831         assertEquals("", l.getScript());
    832 
    833         l = fromLanguageTag("en-f-fooobaaaz", false);
    834         assertEquals("en", l.getLanguage());
    835         assertEquals("", l.getCountry());
    836         assertEquals("", l.getVariant());
    837         assertEquals("", l.getScript());
    838 
    839         l = fromLanguageTag("en-9-baa", false);
    840         assertEquals("en", l.getLanguage());
    841         assertEquals("", l.getCountry());
    842         assertEquals("", l.getVariant());
    843         assertEquals("", l.getScript());
    844     }
    845 
    846     public void test_Builder_unicodeAttributes() {
    847         // Adding and removing attributes
    848         Locale.Builder b = new Locale.Builder();
    849         b.setLanguage("en");
    850 
    851         // Well formed attribute.
    852         b.addUnicodeLocaleAttribute("foooo");
    853 
    854         try {
    855             b.addUnicodeLocaleAttribute("fo");
    856             fail();
    857         } catch (IllformedLocaleException ifle) {
    858         }
    859 
    860         try {
    861             b.removeUnicodeLocaleAttribute("fo");
    862             fail();
    863         } catch (IllformedLocaleException ifle) {
    864         }
    865 
    866         try {
    867             b.addUnicodeLocaleAttribute("greaterthaneightchars");
    868             fail();
    869         } catch (IllformedLocaleException ifle) {
    870         }
    871 
    872         try {
    873             b.removeUnicodeLocaleAttribute("greaterthaneightchars");
    874             fail();
    875         } catch (IllformedLocaleException ifle) {
    876         }
    877 
    878         try {
    879             b.addUnicodeLocaleAttribute(null);
    880             fail();
    881         } catch (NullPointerException npe) {
    882         }
    883 
    884         try {
    885             b.removeUnicodeLocaleAttribute(null);
    886             fail();
    887         } catch (NullPointerException npe) {
    888         }
    889 
    890         Locale l = b.build();
    891         assertEquals("en-u-foooo", l.toLanguageTag());
    892         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
    893 
    894         b.addUnicodeLocaleAttribute("dAtA");
    895         l = b.build();
    896         assertEquals("data-foooo", l.getExtension('u'));
    897         assertTrue(l.getUnicodeLocaleAttributes().contains("data"));
    898         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
    899     }
    900 
    901     public void test_Builder_unicodeKeywords() {
    902         // Adding and removing attributes
    903         Locale.Builder b = new Locale.Builder();
    904         b.setLanguage("en");
    905 
    906         // Key not of length 2.
    907         try {
    908             b.setUnicodeLocaleKeyword("k", "fooo");
    909             fail();
    910         } catch (IllformedLocaleException ifle) {
    911         }
    912 
    913         // Value too short
    914         try {
    915             b.setUnicodeLocaleKeyword("k", "fo");
    916             fail();
    917         } catch (IllformedLocaleException ifle) {
    918         }
    919 
    920         // Value too long
    921         try {
    922             b.setUnicodeLocaleKeyword("k", "foooooooo");
    923             fail();
    924         } catch (IllformedLocaleException ifle) {
    925         }
    926 
    927 
    928         // Null should clear the key.
    929         b.setUnicodeLocaleKeyword("bo", "baaz");
    930         Locale l = b.build();
    931         assertEquals("bo-baaz", l.getExtension('u'));
    932         assertEquals("baaz", l.getUnicodeLocaleType("bo"));
    933 
    934         b = new Locale.Builder();
    935         b.setUnicodeLocaleKeyword("bo", "baaz");
    936         b.setUnicodeLocaleKeyword("bo", null);
    937         l = b.build();
    938         assertNull(l.getExtension('u'));
    939         assertNull(l.getUnicodeLocaleType("bo"));
    940 
    941         // When we set attributes, they should show up before extensions.
    942         b = new Locale.Builder();
    943         b.addUnicodeLocaleAttribute("fooo");
    944         b.addUnicodeLocaleAttribute("gooo");
    945         b.setUnicodeLocaleKeyword("fo", "baz");
    946         b.setUnicodeLocaleKeyword("ka", "kaz");
    947         l = b.build();
    948         assertEquals("fooo-gooo-fo-baz-ka-kaz", l.getExtension('u'));
    949         assertEquals("baz", l.getUnicodeLocaleType("fo"));
    950         assertEquals("kaz", l.getUnicodeLocaleType("ka"));
    951         assertTrue(l.getUnicodeLocaleAttributes().contains("fooo"));
    952         assertTrue(l.getUnicodeLocaleAttributes().contains("gooo"));
    953     }
    954 
    955     public void test_multipleExtensions() {
    956         Locale.Builder b = new Locale.Builder();
    957         b.setLanguage("en");
    958         b.addUnicodeLocaleAttribute("attrib");
    959         b.addUnicodeLocaleAttribute("attrib2");
    960         b.setExtension('f', "fo-baaz-ga-gaaz");
    961         b.setExtension('x', "xo-baaz-ga-gaaz");
    962         b.setExtension('z', "zo-baaz-ga-gaaz");
    963 
    964         Locale l = b.build();
    965         // Implicitly added because we added unicode locale attributes.
    966         assertEquals("attrib-attrib2", l.getExtension('u'));
    967         assertEquals("fo-baaz-ga-gaaz", l.getExtension('f'));
    968         assertEquals("xo-baaz-ga-gaaz", l.getExtension('x'));
    969         assertEquals("zo-baaz-ga-gaaz", l.getExtension('z'));
    970     }
    971 
    972     public void test_immutability() {
    973         Locale.Builder b = new Locale.Builder();
    974         b.setExtension('g', "fooo-baaz-baar");
    975         b.setExtension('u', "foooo-baaar-ba-baaz-ka-kaaz");
    976 
    977         Locale l = b.build();
    978         try {
    979             l.getExtensionKeys().add('g');
    980             fail();
    981         } catch (UnsupportedOperationException expected) {
    982         }
    983 
    984         try {
    985             l.getUnicodeLocaleAttributes().add("fooo");
    986             fail();
    987         } catch (UnsupportedOperationException expected) {
    988         }
    989     }
    990 
    991     public void test_toLanguageTag() {
    992         Locale.Builder b = new Locale.Builder();
    993 
    994         // Empty builder.
    995         Locale l = b.build();
    996         // TODO: Fix this. We should return "und" and not NULL.
    997         // assertEquals("und", l.toLanguageTag());
    998 
    999         // Only language.
   1000         b = new Locale.Builder();
   1001         b.setLanguage("en");
   1002         assertEquals("en", b.build().toLanguageTag());
   1003 
   1004         // Language & Region
   1005         b = new Locale.Builder();
   1006         b.setLanguage("en").setRegion("US");
   1007         assertEquals("en-US", b.build().toLanguageTag());
   1008 
   1009         // Language & Script
   1010         b = new Locale.Builder();
   1011         b.setLanguage("en").setScript("Latn");
   1012         assertEquals("en-Latn", b.build().toLanguageTag());
   1013 
   1014         // Language & Variant
   1015         b = new Locale.Builder();
   1016         b.setLanguage("en").setVariant("foooo");
   1017         assertEquals("en-foooo", b.build().toLanguageTag());
   1018 
   1019         // Language / script & country
   1020         b = new Locale.Builder();
   1021         b.setLanguage("en").setScript("Latn").setRegion("US");
   1022         assertEquals("en-Latn-US", b.build().toLanguageTag());
   1023 
   1024         // Language / script & variant
   1025         b = new Locale.Builder();
   1026         b.setLanguage("en").setScript("Latn").setVariant("foooo");
   1027         assertEquals("en-Latn-foooo", b.build().toLanguageTag());
   1028 
   1029         // Language / script / country / variant.
   1030         b = new Locale.Builder();
   1031         b.setLanguage("en").setScript("Latn").setVariant("foooo").setRegion("US");
   1032         assertEquals("en-Latn-US-foooo", b.build().toLanguageTag());
   1033 
   1034         // Language / extension
   1035         b = new Locale.Builder();
   1036         b.setLanguage("en").setExtension('x', "fooo-baar");
   1037         assertEquals("en-x-fooo-baar", b.build().toLanguageTag());
   1038 
   1039         // Language & multiple extensions (including unicode).
   1040         b = new Locale.Builder();
   1041         b.setLanguage("en");
   1042         b.addUnicodeLocaleAttribute("attrib");
   1043         b.addUnicodeLocaleAttribute("attrib2");
   1044         b.setExtension('f', "fo-baaz-ga-gaaz");
   1045         b.setExtension('x', "xo-baaz-ga-gaaz");
   1046         b.setExtension('z', "zo-baaz-ga-gaaz");
   1047 
   1048         l = b.build();
   1049         // Implicitly added because we added unicode locale attributes.
   1050         assertEquals("attrib-attrib2", l.getExtension('u'));
   1051         assertEquals("fo-baaz-ga-gaaz", l.getExtension('f'));
   1052         assertEquals("xo-baaz-ga-gaaz", l.getExtension('x'));
   1053         assertEquals("zo-baaz-ga-gaaz", l.getExtension('z'));
   1054 
   1055         assertEquals("en-" +
   1056                 "f-fo-baaz-ga-gaaz-" +   // extension tags in lexical order
   1057                 "u-attrib-attrib2-z-zo-baaz-ga-gaaz-" +  // unicode attribs & keywords in lex order
   1058                 "x-xo-baaz-ga-gaaz", // private use extension unmodified.
   1059                 l.toLanguageTag());
   1060     }
   1061 
   1062     public void test_toString() {
   1063         Locale.Builder b = new Locale.Builder();
   1064 
   1065         // Empty builder.
   1066         Locale l = b.build();
   1067         assertEquals("", l.toString());
   1068 
   1069         // Only language.
   1070         b = new Locale.Builder();
   1071         b.setLanguage("en");
   1072         assertEquals("en", b.build().toString());
   1073 
   1074         // Only region
   1075         b = new Locale.Builder();
   1076         b.setRegion("US");
   1077         assertEquals("_US", b.build().toString());
   1078 
   1079         // Language & Region
   1080         b = new Locale.Builder();
   1081         b.setLanguage("en").setRegion("US");
   1082         assertEquals("en_US", b.build().toString());
   1083 
   1084         // Language & Script
   1085         b = new Locale.Builder();
   1086         b.setLanguage("en").setScript("Latn");
   1087         assertEquals("en__#Latn", b.build().toString());
   1088 
   1089         // Language & Variant
   1090         b = new Locale.Builder();
   1091         b.setLanguage("en").setVariant("foooo");
   1092         assertEquals("en__foooo", b.build().toString());
   1093 
   1094         // Language / script & country
   1095         b = new Locale.Builder();
   1096         b.setLanguage("en").setScript("Latn").setRegion("US");
   1097         assertEquals("en_US_#Latn", b.build().toString());
   1098 
   1099         // Language / script & variant
   1100         b = new Locale.Builder();
   1101         b.setLanguage("en").setScript("Latn").setVariant("foooo");
   1102         assertEquals("en__foooo_#Latn", b.build().toString());
   1103 
   1104         // Language / script / country / variant.
   1105         b = new Locale.Builder();
   1106         b.setLanguage("en").setScript("Latn").setVariant("foooo").setRegion("US");
   1107         assertEquals("en_US_foooo_#Latn", b.build().toString());
   1108 
   1109         // Language / extension
   1110         b = new Locale.Builder();
   1111         b.setLanguage("en").setExtension('x', "fooo-baar");
   1112         assertEquals("en__#x-fooo-baar", b.build().toString());
   1113     }
   1114 
   1115     // Tests cases where our "guess" for the output size is incorrect.
   1116     //
   1117     // https://b.corp.google.com/issue?id=13414549
   1118     public void test_toLanguageTag_largerTag() {
   1119         Locale posix = new Locale.Builder()
   1120                 .setLanguage("en").setRegion("US").setVariant("POSIX")
   1121                 .build();
   1122         assertEquals("en-US-POSIX", posix.toLanguageTag());
   1123     }
   1124 
   1125     public void test_forLanguageTag_grandFatheredLocale() {
   1126         // Regular grandfathered locale.
   1127         Locale gaulish = Locale.forLanguageTag("cel-gaulish");
   1128         assertEquals("xtg", gaulish.getLanguage());
   1129         assertEquals("cel-gaulish", gaulish.getExtension(Locale.PRIVATE_USE_EXTENSION));
   1130         assertEquals("", gaulish.getCountry());
   1131         assertEquals("", gaulish.getScript());
   1132         assertEquals("", gaulish.getVariant());
   1133 
   1134         // Irregular grandfathered locale.
   1135         Locale enochian = Locale.forLanguageTag("i-enochian");
   1136         assertEquals("und", enochian.getLanguage());
   1137         assertEquals("i-enochian", enochian.getExtension(Locale.PRIVATE_USE_EXTENSION));
   1138         assertEquals("", enochian.getCountry());
   1139         assertEquals("", enochian.getScript());
   1140         assertEquals("", enochian.getVariant());
   1141     }
   1142 
   1143     // Test case from http://b/16811867
   1144     public void testVariantsCaseSensitive() {
   1145         final Locale locale = new Locale("en", "US", "variant");
   1146         assertEquals("variant", locale.getVariant());
   1147         assertEquals(locale, Locale.forLanguageTag(locale.toLanguageTag()));
   1148     }
   1149 }
   1150