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