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 static java.util.Locale.FilteringMode.AUTOSELECT_FILTERING;
     20 import static java.util.Locale.FilteringMode.EXTENDED_FILTERING;
     21 import static java.util.Locale.FilteringMode.IGNORE_EXTENDED_RANGES;
     22 import static java.util.Locale.FilteringMode.MAP_EXTENDED_RANGES;
     23 import static java.util.Locale.FilteringMode.REJECT_EXTENDED_RANGES;
     24 
     25 import java.io.ObjectInputStream;
     26 import java.text.BreakIterator;
     27 import java.text.Collator;
     28 import java.text.DateFormat;
     29 import java.text.DateFormatSymbols;
     30 import java.text.DecimalFormatSymbols;
     31 import java.text.NumberFormat;
     32 import java.util.ArrayList;
     33 import java.util.Calendar;
     34 import java.util.Collections;
     35 import java.util.IllformedLocaleException;
     36 import java.util.List;
     37 import java.util.Locale;
     38 import java.util.Locale.LanguageRange;
     39 import java.util.MissingResourceException;
     40 
     41 public class LocaleTest extends junit.framework.TestCase {
     42 
     43     public void test_extension_absent() throws Exception {
     44         Locale locale = Locale.forLanguageTag("en-US");
     45         assertFalse(locale.hasExtensions());
     46         assertEquals(locale, locale.stripExtensions());
     47     }
     48 
     49     public void test_extension_builder() throws Exception {
     50         Locale.Builder b = new Locale.Builder();
     51         Locale localeWithoutExtension = b.build();
     52         b.setExtension('g', "FO_ba-BR_bg");
     53         Locale locale = b.build();
     54         assertTrue(locale.hasExtensions());
     55         assertFalse(locale.stripExtensions().hasExtensions());
     56         assertEquals(localeWithoutExtension, locale.stripExtensions());
     57     }
     58 
     59     public void test_extension_languageTag() throws Exception {
     60         Locale lA = Locale.forLanguageTag("en-Latn-US-x-foo");
     61         Locale lB = Locale.forLanguageTag("en-Latn-US");
     62         assertTrue(lA.hasExtensions());
     63         assertFalse(lB.hasExtensions());
     64         assertEquals(lB, lA.stripExtensions());
     65     }
     66 
     67     // http://b/2611311; if there's no display language/country/variant, use the raw codes.
     68     public void test_getDisplayName_invalid() throws Exception {
     69         Locale invalid = new Locale("AaBbCc", "DdEeFf", "GgHhIi");
     70 
     71         assertEquals("aabbcc", invalid.getLanguage());
     72         assertEquals("DDEEFF", invalid.getCountry());
     73         assertEquals("GgHhIi", invalid.getVariant());
     74 
     75         // Android using icu4c < 49.2 returned empty strings for display language, country,
     76         // and variant, but a display name made up of the raw strings.
     77         // Newer releases return slightly different results, but no less unreasonable.
     78         assertEquals("aabbcc", invalid.getDisplayLanguage());
     79         assertEquals("DDEEFF", invalid.getDisplayCountry());
     80         assertEquals("GGHHII", invalid.getDisplayVariant());
     81         assertEquals("aabbcc (DDEEFF,GGHHII)", invalid.getDisplayName());
     82     }
     83 
     84     public void test_getDisplayName_emptyCodes() {
     85         Locale emptyLanguage = new Locale("", "DdeEFf");
     86         assertEquals("", emptyLanguage.getDisplayLanguage());
     87 
     88         Locale emptyCountry = new Locale("AaBbCc", "");
     89         assertEquals("", emptyCountry.getDisplayCountry());
     90 
     91         Locale emptyCountryAndLanguage = new Locale("", "", "Farl");
     92         assertEquals("", emptyCountryAndLanguage.getDisplayLanguage());
     93         assertEquals("", emptyCountryAndLanguage.getDisplayCountry());
     94         assertEquals("Farl", emptyCountryAndLanguage.getDisplayVariant());
     95     }
     96 
     97     // http://b/2611311; if there's no display language/country/variant, use the raw codes.
     98     public void test_getDisplayName_unknown() throws Exception {
     99         Locale unknown = new Locale("xx", "YY", "Traditional");
    100         assertEquals("xx", unknown.getLanguage());
    101         assertEquals("YY", unknown.getCountry());
    102         assertEquals("Traditional", unknown.getVariant());
    103 
    104         assertEquals("xx", unknown.getDisplayLanguage());
    105         assertEquals("YY", unknown.getDisplayCountry());
    106         assertEquals("Traditional", unknown.getDisplayVariant());
    107         assertEquals("xx (YY,Traditional)", unknown.getDisplayName());
    108     }
    109 
    110     public void test_getDisplayName_easy() throws Exception {
    111         assertEquals("English", Locale.ENGLISH.getDisplayLanguage(Locale.ENGLISH));
    112         assertEquals("German", Locale.GERMAN.getDisplayLanguage(Locale.ENGLISH));
    113         assertEquals("Englisch", Locale.ENGLISH.getDisplayLanguage(Locale.GERMAN));
    114         assertEquals("Deutsch", Locale.GERMAN.getDisplayLanguage(Locale.GERMAN));
    115     }
    116 
    117     // https://b/issue?id=13790528
    118     public void test_getDisplayName_withScriptsAndVariants() throws Exception {
    119         // Script + Country.
    120         assertEquals("Chinese (Traditional Han,China)",
    121                 Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US));
    122         // Script + Variant.
    123         assertEquals("Chinese (Traditional Han,VARIANT)",
    124                 Locale.forLanguageTag("zh-Hant-VARIANT").getDisplayName(Locale.US));
    125         // Country + Variant.
    126         assertEquals("Chinese (China,VARIANT)",
    127                 Locale.forLanguageTag("zh-CN-VARIANT").getDisplayName(Locale.US));
    128         // Script + Country + variant.
    129         assertEquals("Chinese (Traditional Han,China,VARIANT)",
    130                 Locale.forLanguageTag("zh-Hant-CN-VARIANT").getDisplayName(Locale.US));
    131     }
    132 
    133     public void test_getDisplayCountry_8870289() throws Exception {
    134         assertEquals("Hong Kong", new Locale("", "HK").getDisplayCountry(Locale.US));
    135         assertEquals("Macau", new Locale("", "MO").getDisplayCountry(Locale.US));
    136         assertEquals("Palestine", new Locale("", "PS").getDisplayCountry(Locale.US));
    137 
    138         assertEquals("Cocos (Keeling) Islands", new Locale("", "CC").getDisplayCountry(Locale.US));
    139         assertEquals("Falkland Islands (Islas Malvinas)", new Locale("", "FK").getDisplayCountry(Locale.US));
    140         assertEquals("Macedonia (FYROM)", new Locale("", "MK").getDisplayCountry(Locale.US));
    141         assertEquals("Myanmar (Burma)", new Locale("", "MM").getDisplayCountry(Locale.US));
    142         assertEquals("Taiwan", new Locale("", "TW").getDisplayCountry(Locale.US));
    143     }
    144 
    145     public void test_tl_and_fil() throws Exception {
    146         // In jb-mr1, we had a last-minute hack to always return "Filipino" because
    147         // icu4c 4.8 didn't have any localizations for fil. (http://b/7291355).
    148         //
    149         // After the icu4c 4.9 upgrade, we could localize "fil" correctly, though we
    150         // needed another hack to supply "fil" instead of "tl" to icu4c. (http://b/8023288).
    151         //
    152         // These hacks have now been reverted, so "tl" really does represent
    153         // tagalog and not filipino.
    154         Locale tl = new Locale("tl");
    155         Locale tl_PH = new Locale("tl", "PH");
    156         assertEquals("Tagalog", tl.getDisplayLanguage(Locale.ENGLISH));
    157         assertEquals("Tagalog", tl_PH.getDisplayLanguage(Locale.ENGLISH));
    158         assertEquals("Tagalog", tl.getDisplayLanguage(tl));
    159         assertEquals("Tagalog", tl_PH.getDisplayLanguage(tl_PH));
    160 
    161         Locale es_MX = new Locale("es", "MX");
    162         assertEquals("tagalo", tl.getDisplayLanguage(es_MX));
    163         assertEquals("tagalo", tl_PH.getDisplayLanguage(es_MX));
    164 
    165         // Assert that we can deal with "fil" correctly, since we've switched
    166         // to using "fil" for Filipino, and not "tl". (http://b/15873165).
    167         Locale fil = new Locale("fil");
    168         Locale fil_PH = new Locale("fil", "PH");
    169         assertEquals("Filipino", fil.getDisplayLanguage(Locale.ENGLISH));
    170         assertEquals("Filipino", fil_PH.getDisplayLanguage(Locale.ENGLISH));
    171         assertEquals("Filipino", fil.getDisplayLanguage(fil));
    172         assertEquals("Filipino", fil_PH.getDisplayLanguage(fil_PH));
    173 
    174         assertEquals("filipino", fil.getDisplayLanguage(es_MX));
    175         assertEquals("filipino", fil_PH.getDisplayLanguage(es_MX));
    176     }
    177 
    178     // http://b/3452611; Locale.getDisplayLanguage fails for the obsolete language codes.
    179     public void test_getDisplayName_obsolete() throws Exception {
    180         // he (new) -> iw (obsolete)
    181         assertObsolete("he", "iw", "");
    182         // id (new) -> in (obsolete)
    183         assertObsolete("id", "in", "Indonesia");
    184     }
    185 
    186     private static void assertObsolete(String newCode, String oldCode, String displayName) {
    187         // Either code should get you the same locale.
    188         Locale newLocale = new Locale(newCode);
    189         Locale oldLocale = new Locale(oldCode);
    190         assertEquals(newLocale, oldLocale);
    191 
    192         // No matter what code you used to create the locale, you should get the old code back.
    193         assertEquals(oldCode, newLocale.getLanguage());
    194         assertEquals(oldCode, oldLocale.getLanguage());
    195 
    196         // Check we get the right display name.
    197         assertEquals(displayName, newLocale.getDisplayLanguage(newLocale));
    198         assertEquals(displayName, oldLocale.getDisplayLanguage(newLocale));
    199         assertEquals(displayName, newLocale.getDisplayLanguage(oldLocale));
    200         assertEquals(displayName, oldLocale.getDisplayLanguage(oldLocale));
    201 
    202         // Check that none of the 'getAvailableLocales' methods are accidentally returning two
    203         // equal locales (because to ICU they're different, but we mangle one into the other).
    204         assertOnce(newLocale, BreakIterator.getAvailableLocales());
    205         assertOnce(newLocale, Calendar.getAvailableLocales());
    206         assertOnce(newLocale, Collator.getAvailableLocales());
    207         assertOnce(newLocale, DateFormat.getAvailableLocales());
    208         assertOnce(newLocale, DateFormatSymbols.getAvailableLocales());
    209         assertOnce(newLocale, NumberFormat.getAvailableLocales());
    210         assertOnce(newLocale, Locale.getAvailableLocales());
    211     }
    212 
    213     private static void assertOnce(Locale element, Locale[] array) {
    214         int count = 0;
    215         for (Locale l : array) {
    216             if (l.equals(element)) {
    217                 ++count;
    218             }
    219         }
    220         assertEquals(1, count);
    221     }
    222 
    223     public void test_getISO3Country() {
    224         // Empty country code.
    225         assertEquals("", new Locale("en", "").getISO3Country());
    226 
    227         // Invalid country code.
    228         try {
    229             assertEquals("", new Locale("en", "XX").getISO3Country());
    230             fail();
    231         } catch (MissingResourceException expected) {
    232             assertEquals("FormatData_en_XX", expected.getClassName());
    233             assertEquals("ShortCountry", expected.getKey());
    234         }
    235 
    236         // Valid country code.
    237         assertEquals("CAN", new Locale("", "CA").getISO3Country());
    238         assertEquals("CAN", new Locale("en", "CA").getISO3Country());
    239         assertEquals("CAN", new Locale("xx", "CA").getISO3Country());
    240 
    241         // 3 letter country codes.
    242         assertEquals("CAN", new Locale("en", "CAN").getISO3Country());
    243         assertEquals("CAN", new Locale("frankenderp", "CAN").getISO3Country());
    244     }
    245 
    246     public void test_getISO3Language() {
    247         // Empty language code.
    248         assertEquals("", new Locale("", "US").getISO3Language());
    249 
    250         // Invalid language code.
    251         try {
    252             assertEquals("", new Locale("xx", "US").getISO3Language());
    253             fail();
    254         } catch (MissingResourceException expected) {
    255             assertEquals("FormatData_xx_US", expected.getClassName());
    256             assertEquals("ShortLanguage", expected.getKey());
    257         }
    258 
    259         // Valid language code.
    260         assertEquals("eng", new Locale("en", "").getISO3Language());
    261         assertEquals("eng", new Locale("en", "CA").getISO3Language());
    262         assertEquals("eng", new Locale("en", "XX").getISO3Language());
    263 
    264         // 3 letter language code.
    265         assertEquals("eng", new Locale("eng", "USA").getISO3Language());
    266         assertEquals("eng", new Locale("eng", "US").getISO3Language());
    267     }
    268 
    269     public void test_Builder_setLanguage() {
    270         Locale.Builder b = new Locale.Builder();
    271 
    272         // Should normalize to lower case.
    273         b.setLanguage("EN");
    274         assertEquals("en", b.build().getLanguage());
    275 
    276         b = new Locale.Builder();
    277 
    278         // Too short.
    279         try {
    280             b.setLanguage("e");
    281             fail();
    282         } catch (IllformedLocaleException expected) {
    283         }
    284 
    285         // Too long
    286         try {
    287             // note: pre-openJdk Locale assumed that language will be between
    288             // 2-3 characters. openJdk accepts 2-8 character languages.
    289             b.setLanguage("foobarbar");
    290             fail();
    291         } catch (IllformedLocaleException expected) {
    292         }
    293 
    294         // Contains non ASCII characters
    295         try {
    296             b.setLanguage("");
    297             fail();
    298         } catch (IllformedLocaleException expected) {
    299         }
    300 
    301         // Null or empty languages must clear state.
    302         b = new Locale.Builder();
    303         b.setLanguage("en");
    304         b.setLanguage(null);
    305         assertEquals("", b.build().getLanguage());
    306 
    307         b = new Locale.Builder();
    308         b.setLanguage("en");
    309         b.setLanguage("");
    310         assertEquals("", b.build().getLanguage());
    311     }
    312 
    313     public void test_Builder_setRegion() {
    314         Locale.Builder b = new Locale.Builder();
    315 
    316         // Should normalize to upper case.
    317         b.setRegion("us");
    318         assertEquals("US", b.build().getCountry());
    319 
    320         b = new Locale.Builder();
    321 
    322         // Too short.
    323         try {
    324             b.setRegion("e");
    325             fail();
    326         } catch (IllformedLocaleException expected) {
    327         }
    328 
    329         // Too long
    330         try {
    331             b.setRegion("USA");
    332             fail();
    333         } catch (IllformedLocaleException expected) {
    334         }
    335 
    336         // Contains non ASCII characters
    337         try {
    338             b.setLanguage("");
    339             fail();
    340         } catch (IllformedLocaleException expected) {
    341         }
    342 
    343         // Null or empty regions must clear state.
    344         b = new Locale.Builder();
    345         b.setRegion("US");
    346         b.setRegion(null);
    347         assertEquals("", b.build().getCountry());
    348 
    349         b = new Locale.Builder();
    350         b.setRegion("US");
    351         b.setRegion("");
    352         assertEquals("", b.build().getCountry());
    353     }
    354 
    355     public void test_Builder_setVariant() {
    356         Locale.Builder b = new Locale.Builder();
    357 
    358         // Should normalize "_" to "-"
    359         b = new Locale.Builder();
    360         b.setVariant("vArIaNt-VaRiAnT-VARIANT");
    361         assertEquals("vArIaNt_VaRiAnT_VARIANT", b.build().getVariant());
    362 
    363         b = new Locale.Builder();
    364         // Too short
    365         try {
    366             b.setVariant("shor");
    367             fail();
    368         } catch (IllformedLocaleException expected) {
    369         }
    370 
    371         // Too long
    372         try {
    373             b.setVariant("waytoolong");
    374             fail();
    375         } catch (IllformedLocaleException expected) {
    376         }
    377 
    378         try {
    379             b.setVariant("foooo-foooo-fo");
    380             fail();
    381         } catch (IllformedLocaleException expected) {
    382         }
    383 
    384         // Special case. Variants of length 4 are allowed when the first
    385         // character is a digit.
    386         b.setVariant("0ABC");
    387         assertEquals("0ABC", b.build().getVariant());
    388 
    389         b = new Locale.Builder();
    390         b.setVariant("variant");
    391         b.setVariant(null);
    392         assertEquals("", b.build().getVariant());
    393 
    394         b = new Locale.Builder();
    395         b.setVariant("variant");
    396         b.setVariant("");
    397         assertEquals("", b.build().getVariant());
    398     }
    399 
    400     public void test_Builder_setLocale() {
    401         // Default case.
    402         Locale.Builder b = new Locale.Builder();
    403         b.setLocale(Locale.US);
    404         assertEquals("en", b.build().getLanguage());
    405         assertEquals("US", b.build().getCountry());
    406 
    407         // Should throw when locale is malformed.
    408         // - Bad language
    409         Locale bad = new Locale("e", "US");
    410         b = new Locale.Builder();
    411         try {
    412             b.setLocale(bad);
    413             fail();
    414         } catch (IllformedLocaleException expected) {
    415         }
    416         // - Bad country
    417         bad = new Locale("en", "USA");
    418         try {
    419             b.setLocale(bad);
    420             fail();
    421         } catch (IllformedLocaleException expected) {
    422         }
    423 
    424         // - Bad variant
    425         bad = new Locale("en", "US", "c");
    426         try {
    427             b.setLocale(bad);
    428             fail();
    429         } catch (IllformedLocaleException expected) {
    430         }
    431 
    432         // Test values are normalized as they should be
    433         b = new Locale.Builder();
    434         Locale good = new Locale("EN", "us", "variant-VARIANT");
    435         b.setLocale(good);
    436         Locale l = b.build();
    437         assertEquals("en", l.getLanguage());
    438         assertEquals("US", l.getCountry());
    439         assertEquals("variant_VARIANT", l.getVariant());
    440 
    441         // Test that none of the existing fields are messed with
    442         // if the locale update fails.
    443         b = new Locale.Builder();
    444         b.setLanguage("fr").setRegion("FR");
    445 
    446         try {
    447             b.setLocale(bad);
    448             fail();
    449         } catch (IllformedLocaleException expected) {
    450         }
    451 
    452         l = b.build();
    453         assertEquals("fr", l.getLanguage());
    454         assertEquals("FR", l.getCountry());
    455     }
    456 
    457     public void test_Builder_setScript() {
    458         Locale.Builder b = new Locale.Builder();
    459 
    460         // Should normalize variants to lower case.
    461         b.setScript("lAtN");
    462         assertEquals("Latn", b.build().getScript());
    463 
    464         b = new Locale.Builder();
    465         // Too short
    466         try {
    467             b.setScript("lat");
    468             fail();
    469         } catch (IllformedLocaleException expected) {
    470         }
    471 
    472         // Too long
    473         try {
    474             b.setScript("latin");
    475             fail();
    476         } catch (IllformedLocaleException expected) {
    477         }
    478 
    479         b = new Locale.Builder();
    480         b.setScript("Latn");
    481         b.setScript(null);
    482         assertEquals("", b.build().getScript());
    483 
    484         b = new Locale.Builder();
    485         b.setScript("Latn");
    486         b.setScript("");
    487         assertEquals("", b.build().getScript());
    488     }
    489 
    490     public void test_Builder_clear() {
    491         Locale.Builder b = new Locale.Builder();
    492         b.setLanguage("en").setScript("Latn").setRegion("US")
    493                 .setVariant("POSIX").setExtension('g', "foo")
    494                 .setUnicodeLocaleKeyword("fo", "baar")
    495                 .addUnicodeLocaleAttribute("baaaaz");
    496 
    497         Locale l = b.clear().build();
    498         assertEquals("", l.getLanguage());
    499         assertEquals("", l.getCountry());
    500         assertEquals("", l.getVariant());
    501         assertEquals("", l.getScript());
    502         assertTrue(l.getExtensionKeys().isEmpty());
    503     }
    504 
    505     public void test_Builder_setExtension() {
    506         Locale.Builder b = new Locale.Builder();
    507         b.setExtension('g', "FO_ba-BR_bg");
    508 
    509         Locale l = b.build();
    510         assertEquals("fo-ba-br-bg", l.getExtension('g'));
    511 
    512         b = new Locale.Builder();
    513 
    514         // Too short
    515         try {
    516             b.setExtension('g', "fo-ba-br-x");
    517             fail();
    518         } catch (IllformedLocaleException expected) {
    519         }
    520 
    521         // Too long
    522         try {
    523             b.setExtension('g', "fo-ba-br-extension");
    524             fail();
    525         } catch (IllformedLocaleException expected) {
    526         }
    527 
    528         // Special case, the private use extension allows single char subtags.
    529         b.setExtension(Locale.PRIVATE_USE_EXTENSION, "fo-ba-br-m");
    530         l = b.build();
    531         assertEquals("fo-ba-br-m", l.getExtension('x'));
    532 
    533         // Special case, the unicode locale extension must be parsed into
    534         // its individual components. The correctness of the parse is tested
    535         // in test_parseUnicodeExtension.
    536         b.setExtension(Locale.UNICODE_LOCALE_EXTENSION, "foooo_BaaaR-BA_Baz-bI_BIZ");
    537         l = b.build();
    538         // Note that attributes and keywords are sorted alphabetically.
    539         assertEquals("baaar-foooo-ba-baz-bi-biz", l.getExtension('u'));
    540 
    541         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
    542         assertTrue(l.getUnicodeLocaleAttributes().contains("baaar"));
    543         assertEquals("baz", l.getUnicodeLocaleType("ba"));
    544         assertEquals("biz", l.getUnicodeLocaleType("bi"));
    545     }
    546 
    547     public void test_Builder_clearExtensions() {
    548         Locale.Builder b = new Locale.Builder();
    549         b.setExtension('g', "FO_ba-BR_bg");
    550         b.setExtension(Locale.PRIVATE_USE_EXTENSION, "fo-ba-br-m");
    551         b.clearExtensions();
    552 
    553         assertTrue(b.build().getExtensionKeys().isEmpty());
    554     }
    555 
    556     private static Locale fromLanguageTag(String languageTag, boolean useBuilder) {
    557         if (useBuilder) {
    558             return (new Locale.Builder().setLanguageTag(languageTag).build());
    559         } else {
    560             return Locale.forLanguageTag(languageTag);
    561         }
    562     }
    563 
    564     private void test_setLanguageTag_wellFormedsingleSubtag(boolean useBuilder) {
    565         Locale l = fromLanguageTag("en", useBuilder);
    566         assertEquals("en", l.getLanguage());
    567 
    568         l = fromLanguageTag("eng", useBuilder);
    569         assertEquals("eng", l.getLanguage());
    570     }
    571 
    572     private void test_setLanguageTag_twoWellFormedSubtags(boolean useBuilder) {
    573         Locale l =  fromLanguageTag("en-US", useBuilder);
    574         assertEquals("en", l.getLanguage());
    575         assertEquals("US", l.getCountry());
    576 
    577         l =  fromLanguageTag("eng-419", useBuilder);
    578         assertEquals("eng", l.getLanguage());
    579         assertEquals("419", l.getCountry());
    580 
    581         // Script tags shouldn't be mis-recognized as regions.
    582         l =  fromLanguageTag("en-Latn", useBuilder);
    583         assertEquals("en", l.getLanguage());
    584         assertEquals("", l.getCountry());
    585         assertEquals("Latn", l.getScript());
    586 
    587         // Neither should variant tags.
    588         l =  fromLanguageTag("en-POSIX", useBuilder);
    589         assertEquals("en", l.getLanguage());
    590         assertEquals("", l.getCountry());
    591         assertEquals("", l.getScript());
    592         assertEquals("POSIX", l.getVariant());
    593     }
    594 
    595     public void test_Builder_setLanguageTag_malformedTags() {
    596         try {
    597             fromLanguageTag("a", true);
    598             fail();
    599         } catch (IllformedLocaleException ifle) {
    600         }
    601 
    602         // Three subtags
    603         // lang-region-illformedvariant
    604         try {
    605             fromLanguageTag("en-US-BA", true);
    606             fail();
    607         } catch (IllformedLocaleException expected) {
    608         }
    609 
    610         // lang-variant-illformedvariant
    611         try {
    612             fromLanguageTag("en-FOOOO-BA", true);
    613             fail();
    614         } catch (IllformedLocaleException expected) {
    615         }
    616 
    617         // Four or more sub tags
    618         try {
    619             fromLanguageTag("en-US-POSIX-P2", true);
    620             fail();
    621         } catch (IllformedLocaleException expected) {
    622         }
    623 
    624         try {
    625             fromLanguageTag("en-Latn-US-P2", true);
    626             fail();
    627         } catch (IllformedLocaleException expected) {
    628         }
    629 
    630         // Extensions
    631         // Ill-formed empty extension.
    632         try {
    633             fromLanguageTag("en-f-f", true);
    634             fail();
    635         } catch (IllformedLocaleException expected) {
    636         }
    637 
    638         // Ill-formed empty extension.
    639         try {
    640             fromLanguageTag("en-f", true);
    641             fail();
    642         } catch (IllformedLocaleException expected) {
    643         }
    644 
    645         // Two extension keys in a row (i.e, another case of an ill-formed
    646         // empty exception).
    647         try {
    648             fromLanguageTag("en-f-g-fo-baar", true);
    649             fail();
    650         } catch (IllformedLocaleException expected) {
    651         }
    652 
    653         // Dangling empty key after a well formed extension.
    654         try {
    655             fromLanguageTag("en-f-fo-baar-g", true);
    656             fail();
    657         } catch (IllformedLocaleException expected) {
    658         }
    659 
    660         // Ill-formed extension with long subtag.
    661         try {
    662             fromLanguageTag("en-f-fooobaaaz", true);
    663             fail();
    664         } catch (IllformedLocaleException expected) {
    665         }
    666     }
    667 
    668     private void test_setLanguageTag_threeWellFormedSubtags(boolean useBuilder) {
    669         // lang-region-variant
    670         Locale l = fromLanguageTag("en-US-FOOOO", useBuilder);
    671         assertEquals("en", l.getLanguage());
    672         assertEquals("US", l.getCountry());
    673         assertEquals("", l.getScript());
    674         assertEquals("FOOOO", l.getVariant());
    675 
    676         // lang-script-variant
    677         l = fromLanguageTag("en-Latn-FOOOO", useBuilder);
    678         assertEquals("en", l.getLanguage());
    679         assertEquals("", l.getCountry());
    680         assertEquals("Latn", l.getScript());
    681         assertEquals("FOOOO", l.getVariant());
    682 
    683         // lang-script-region
    684         l = fromLanguageTag("en-Latn-US", useBuilder);
    685         assertEquals("en", l.getLanguage());
    686         assertEquals("US", l.getCountry());
    687         assertEquals("Latn", l.getScript());
    688         assertEquals("", l.getVariant());
    689 
    690         // lang-variant-variant
    691         l = fromLanguageTag("en-FOOOO-BAAAR", useBuilder);
    692         assertEquals("en", l.getLanguage());
    693         assertEquals("", l.getCountry());
    694         assertEquals("", l.getScript());
    695         assertEquals("FOOOO_BAAAR", l.getVariant());
    696     }
    697 
    698     private void test_setLanguageTag_fourOrMoreWellFormedSubtags(boolean useBuilder) {
    699         // lang-script-region-variant.
    700         Locale l = fromLanguageTag("en-Latn-US-foooo", useBuilder);
    701         assertEquals("en", l.getLanguage());
    702         assertEquals("Latn", l.getScript());
    703         assertEquals("US", l.getCountry());
    704         assertEquals("foooo", l.getVariant());
    705 
    706         // Variant with multiple subtags.
    707         l = fromLanguageTag("en-Latn-US-foooo-gfffh", useBuilder);
    708         assertEquals("en", l.getLanguage());
    709         assertEquals("Latn", l.getScript());
    710         assertEquals("US", l.getCountry());
    711         assertEquals("foooo_gfffh", l.getVariant());
    712 
    713         // Variant with 3 subtags. POSIX shouldn't be recognized
    714         // as a region or a script.
    715         l = fromLanguageTag("en-POSIX-P2003-P2004", useBuilder);
    716         assertEquals("en", l.getLanguage());
    717         assertEquals("", l.getScript());
    718         assertEquals("", l.getCountry());
    719         assertEquals("POSIX_P2003_P2004", l.getVariant());
    720 
    721         // lang-script-variant-variant.
    722         l = fromLanguageTag("en-Latn-POSIX-P2003", useBuilder);
    723         assertEquals("en", l.getLanguage());
    724         assertEquals("Latn", l.getScript());
    725         assertEquals("", l.getCountry());
    726         assertEquals("POSIX_P2003", l.getVariant());
    727 
    728         // lang-region-variant-variant
    729         l = fromLanguageTag("en-US-POSIX-P2003", useBuilder);
    730         assertEquals("en", l.getLanguage());
    731         assertEquals("", l.getScript());
    732         assertEquals("US", l.getCountry());
    733         assertEquals("POSIX_P2003", l.getVariant());
    734     }
    735 
    736     private void test_setLanguageTag_withWellFormedExtensions(boolean useBuilder) {
    737         Locale l = fromLanguageTag("en-Latn-GB-foooo-g-fo-bar-baaz", useBuilder);
    738         assertEquals("en", l.getLanguage());
    739         assertEquals("Latn", l.getScript());
    740         assertEquals("GB", l.getCountry());
    741         assertEquals("foooo", l.getVariant());
    742         assertEquals("fo-bar-baaz", l.getExtension('g'));
    743 
    744         // Multiple extensions
    745         l = fromLanguageTag("en-Latn-US-foooo-g-fo-bar-h-go-gaz", useBuilder);
    746         assertEquals("en", l.getLanguage());
    747         assertEquals("Latn", l.getScript());
    748         assertEquals("US", l.getCountry());
    749         assertEquals("foooo", l.getVariant());
    750         assertEquals("fo-bar", l.getExtension('g'));
    751         assertEquals("go-gaz", l.getExtension('h'));
    752 
    753         // Unicode locale extension.
    754         l = fromLanguageTag("en-Latn-US-foooo-u-koooo-fo-bar", useBuilder);
    755         assertEquals("en", l.getLanguage());
    756         assertEquals("Latn", l.getScript());
    757         assertEquals("US", l.getCountry());
    758         assertEquals("koooo-fo-bar", l.getExtension('u'));
    759         assertTrue(l.getUnicodeLocaleAttributes().contains("koooo"));
    760         assertEquals("bar", l.getUnicodeLocaleType("fo"));
    761 
    762         // Extensions without variants
    763         l = fromLanguageTag("en-Latn-US-f-fo", useBuilder);
    764         assertEquals("en", l.getLanguage());
    765         assertEquals("Latn", l.getScript());
    766         assertEquals("US", l.getCountry());
    767         assertEquals("fo", l.getExtension('f'));
    768 
    769         l = fromLanguageTag("en-Latn-f-fo", useBuilder);
    770         assertEquals("en", l.getLanguage());
    771         assertEquals("Latn", l.getScript());
    772         assertEquals("fo", l.getExtension('f'));
    773 
    774         l = fromLanguageTag("en-f-fo", useBuilder);
    775         assertEquals("en", l.getLanguage());
    776         assertEquals("", l.getScript());
    777         assertEquals("", l.getCountry());
    778         assertEquals("fo", l.getExtension('f'));
    779 
    780         l = fromLanguageTag("en-f-fo-x-a-b-c-d-e-fo", useBuilder);
    781         assertEquals("en", l.getLanguage());
    782         assertEquals("", l.getScript());
    783         assertEquals("", l.getCountry());
    784         assertEquals("fo", l.getExtension('f'));
    785         assertEquals("a-b-c-d-e-fo", l.getExtension('x'));
    786     }
    787 
    788     /**
    789      * Tests filtering locales using basic language ranges (without "*").
    790      */
    791     public void test_filter_basic() {
    792         List<String> tags = tagsOf(
    793             "en-US",
    794             "en-Latn-US",
    795             "zh-Hant-TW",
    796             "es-419",
    797             "fr-FR",
    798             "ja-JP"
    799         );
    800         List<LanguageRange> ranges = new ArrayList<>();
    801         ranges.add(new LanguageRange("en-US"));
    802 
    803         // By default, basic filtering is used for basic language ranges
    804         assertFilter(tagsOf("en-US"), ranges, tags);
    805 
    806         // Since no extended ranges are given, these should produce the same result
    807         assertFilter(tagsOf("en-US"), ranges, tags, AUTOSELECT_FILTERING);
    808         assertFilter(tagsOf("en-US"), ranges, tags, REJECT_EXTENDED_RANGES);
    809         assertFilter(tagsOf("en-US"), ranges, tags, IGNORE_EXTENDED_RANGES);
    810 
    811         // EXTENDED_FILTERING can be enabled explicitly even when the priority
    812         // list only contains basic; then, en-US also matches en-Latn-US.
    813         assertFilter(tagsOf("en-US", "en-Latn-US"), ranges, tags, EXTENDED_FILTERING);
    814 
    815         ranges.add(new LanguageRange("zh-Hant-TW"));
    816         assertFilter(tagsOf("en-US", "zh-Hant-TW"), ranges, tags);
    817     }
    818 
    819     /**
    820      * Tests that filtering is case insensitive.
    821      */
    822     public void test_filter_caseInsensitive() {
    823         List<String> tags = tagsOf("de-DE", "de-Latn-DE", "ja-jp");
    824 
    825         assertFilter(tagsOf("de-DE"), languageRangesOf("dE-De"), tags);
    826         assertFilter(tagsOf("ja-jp"), languageRangesOf("ja-JP"), tags);
    827         assertFilter(tagsOf("ja-jp"), languageRangesOf("JA-jp"), tags);
    828     }
    829 
    830     /**
    831      * Tests filtering locales using extended language ranges (with "*"), per
    832      * the example from RFC 4647 section 3.3.2
    833      */
    834     public void test_filter_extended() {
    835         List<LanguageRange> priorityList = languageRangesOf("de-DE", "de-*-DE");
    836         List<String> tags = tagsOf(
    837             "de", // not matched: missing 'DE'
    838             "de-DE", // German, as used in Germany
    839             "de-de", // German, as used in Germany
    840             "de-Latn-DE", // Latin script
    841             "de-Latf-DE", // Fraktur variant of Latin script
    842             "de-DE-x-goethe", // private-use subtag
    843             "de-Latn-DE-1996",
    844             "de-Deva", // not matched: 'Deva' not equal to 'DE'
    845             "de-Deva-DE", // Devanagari script
    846             "de-x-DE" // not matched: singleton 'x' occurs before 'DE'
    847         );
    848 
    849         List<String> filteredTags = tagsOf(
    850             "de-DE", // German, as used in Germany
    851             "de-Latn-DE", // Latin script
    852             "de-Latf-DE", // Fraktur variant of Latin script
    853             "de-DE-x-goethe", // private-use subtag
    854             "de-Latn-DE-1996",
    855             "de-Deva-DE" // Devanagari script
    856         );
    857 
    858         assertFilter(filteredTags, priorityList, tags, EXTENDED_FILTERING);
    859 
    860         // Because the priority list contains an extended language range, filtering
    861         // should default to extended, so default filtering should yield the same results:
    862         assertFilter(filteredTags, priorityList, tags);
    863         assertFilter(filteredTags, priorityList, tags, AUTOSELECT_FILTERING);
    864 
    865         // Ignoring the extended range (de-*-DE) matches only a single language tag, "de-DE"
    866         assertFilter(tagsOf("de-DE", "de-DE-x-goethe"), priorityList, tags, IGNORE_EXTENDED_RANGES);
    867     }
    868 
    869     /**
    870      * Tests that filtering with {@link Locale.FilteringMode#REJECT_EXTENDED_RANGES}
    871      * throws IllegalArgumentException if passed an extended tag / language range.
    872      */
    873     public void test_filter_extended_reject() {
    874         try {
    875             Locale.filter(
    876                 languageRangesOf("de-DE", "de-*-DE"),
    877                 localesOf("de-DE", "fr-FR"),
    878                 REJECT_EXTENDED_RANGES);
    879             fail();
    880         } catch (IllegalArgumentException expected) {
    881         }
    882 
    883         try {
    884             Locale.filterTags(
    885                 languageRangesOf("de-DE", "de-*-DE"),
    886                 tagsOf("de-DE", "fr-FR"),
    887                 REJECT_EXTENDED_RANGES);
    888             fail();
    889         } catch (IllegalArgumentException expected) {
    890         }
    891     }
    892 
    893     /**
    894      * Checks that a '*' occurring in a LanguageRange is interpreted in compliance
    895      * with RFC 4647 section 3.2: if the first subtag is a '*' then the entire range
    896      * is treated as "*", otherwise each wildcard subtag is removed.
    897      */
    898     public void test_filter_extended_wildcardInLanguageRange() {
    899         List<String> tags = tagsOf("en-US", "de-DE", "en-AU", "en-Latn-US");
    900         // en-*-US is treated as "en-US", so only en-US matches
    901         assertFilter(tagsOf("en-US"), languageRangesOf("en-*-US"), tags, MAP_EXTENDED_RANGES);
    902 
    903         // *-US is treated as "*", so all locales match
    904         assertFilter(tags, languageRangesOf("*-US"), tags, MAP_EXTENDED_RANGES);
    905 
    906         // Same behavior with just "*"
    907         assertFilter(tags, languageRangesOf("*"), tags, MAP_EXTENDED_RANGES);
    908     }
    909 
    910     /**
    911      * Tests that a '*' in a Locale in the priority list matches a subtag only
    912      * when extended filtering is used; note that this is different from a
    913      * '*' occuring in a LanguageRange, where it is ignored.
    914      */
    915     public void test_filter_extended_wildcardInPriorityList() {
    916         List<String> tags = tagsOf("de-DE", "de-Latn-DE", "ja-JP");
    917         assertFilter(tagsOf("de-DE", "de-Latn-DE"),
    918             languageRangesOf("dE-*-De"), tags);
    919         assertFilter(tagsOf("de-DE", "de-Latn-DE"),
    920             languageRangesOf("dE-De"), tags, EXTENDED_FILTERING);
    921     }
    922 
    923     public void test_filter_noMatch() {
    924         List<String> noTag = Collections.emptyList();
    925 
    926         List<String> tags = tagsOf("en-US", "fr-Fr", "de-DE");
    927 
    928         assertFilter(noTag, languageRangesOf("en-AU"), tags);
    929         assertFilter(noTag, languageRangesOf("es-419"), tags);
    930         assertFilter(noTag, languageRangesOf("zh-*-TW"), tags);
    931     }
    932 
    933     /**
    934      * Tests that various methods throw NullPointerException when given {@code null}
    935      * as an argument.
    936      */
    937     public void test_filter_nullArguments() {
    938         List<String> tags = tagsOf("de-DE", "de-Latn-DE");
    939         List<Locale> locales = localesOf(tags);
    940         List<LanguageRange> languageRanges = languageRangesOf("en-*-US", "de-DE");
    941 
    942         assertThrowsNpe(() -> { Locale.filter(null, locales); });
    943         assertThrowsNpe(() -> { Locale.filter(languageRanges, null); });
    944 
    945         assertThrowsNpe(() -> { Locale.filterTags(null, tags); });
    946         assertThrowsNpe(() -> { Locale.filterTags(languageRanges, null); });
    947 
    948         // The documentation doesn't say whether FilteringMode is allowed to be
    949         // null or what the sematnics of that null are; currently it is allowed.
    950         // This test ensures that we are aware if we change this behavior in future.
    951         List<Locale> filteredLocales = Locale.filter(languageRanges, locales, null);
    952         List<String> filteredTags = Locale.filterTags(languageRanges, tags, null);
    953         assertEquals(localesOf("de-DE"), filteredLocales);
    954         assertEquals(tagsOf("de-DE"), filteredTags);
    955     }
    956 
    957     /**
    958      * Tests that filtered locales are returned in priority order.
    959      */
    960     public void test_filter_priorityOrder() {
    961         List<LanguageRange> priorityList = languageRangesOf("zh-Hant-TW", "en-US");
    962 
    963         List<String> tags = tagsOf(
    964             "en-US",
    965             "zh-Hant-TW",
    966             "es-419",
    967             "fr-FR"
    968         );
    969         assertFilter(tagsOf("zh-Hant-TW", "en-US"), languageRangesOf("zh-Hant-TW", "en-US"), tags);
    970         assertFilter(tagsOf("en-US", "zh-Hant-TW"), languageRangesOf("en-US", "zh-Hant-TW"), tags);
    971     }
    972 
    973     /**
    974      * Tests that the List returned by the various {@code filter} methods is modifiable,
    975      * as specified by the documentation.
    976      */
    977     public void test_filter_resultIsModifiable_locales() {
    978         List<LanguageRange> priorityList = languageRangesOf("de-DE", "de-*-DE");
    979         List<Locale> locales = localesOf("de-DE", "de-Latn-DE", "ja-JP");
    980 
    981         Locale dummy = Locale.FRANCE;
    982         // should not throw
    983         Locale.filter(priorityList, locales).add(dummy);
    984         Locale.filter(priorityList, locales, AUTOSELECT_FILTERING).add(dummy);
    985         Locale.filter(priorityList, locales, EXTENDED_FILTERING).add(dummy);
    986         Locale.filter(priorityList, locales, IGNORE_EXTENDED_RANGES).add(dummy);
    987         Locale.filter(priorityList, locales, MAP_EXTENDED_RANGES).add(dummy);
    988         Locale.filter(languageRangesOf("de-DE"), locales, REJECT_EXTENDED_RANGES).add(dummy);
    989     }
    990 
    991     public void test_filter_resultIsModifiable_tags() {
    992         List<LanguageRange> priorityList = languageRangesOf("de-DE", "de-*-DE");
    993         List<String> tags = tagsOf("de-DE", "de-Latn-DE", "ja-JP");
    994 
    995         String dummy = "fr-FR";
    996         // should not throw
    997         Locale.filterTags(priorityList, tags).add(dummy);
    998         Locale.filterTags(priorityList, tags, AUTOSELECT_FILTERING).add(dummy);
    999         Locale.filterTags(priorityList, tags, EXTENDED_FILTERING).add(dummy);
   1000         Locale.filterTags(priorityList, tags, IGNORE_EXTENDED_RANGES).add(dummy);
   1001         Locale.filterTags(priorityList, tags, MAP_EXTENDED_RANGES).add(dummy);
   1002         Locale.filterTags(languageRangesOf("de-DE"), tags, REJECT_EXTENDED_RANGES).add(dummy);
   1003     }
   1004 
   1005     public void test_forLanguageTag() {
   1006         test_setLanguageTag_wellFormedsingleSubtag(false);
   1007         test_setLanguageTag_twoWellFormedSubtags(false);
   1008         test_setLanguageTag_threeWellFormedSubtags(false);
   1009         test_setLanguageTag_fourOrMoreWellFormedSubtags(false);
   1010         test_setLanguageTag_withWellFormedExtensions(false);
   1011     }
   1012 
   1013     public void test_Builder_setLanguageTag() {
   1014         test_setLanguageTag_wellFormedsingleSubtag(true);
   1015         test_setLanguageTag_twoWellFormedSubtags(true);
   1016         test_setLanguageTag_threeWellFormedSubtags(true);
   1017         test_setLanguageTag_fourOrMoreWellFormedSubtags(true);
   1018         test_setLanguageTag_withWellFormedExtensions(true);
   1019     }
   1020 
   1021     public void test_getDisplayScript() {
   1022         Locale.Builder b = new Locale.Builder();
   1023         b.setLanguage("en").setRegion("US").setScript("Latn");
   1024 
   1025         Locale l = b.build();
   1026 
   1027         // getAndSetDefaultForTest(uncategorizedLocale, displayLocale, formatLocale)
   1028         Locales locales = Locales.getAndSetDefaultForTest(Locale.US, Locale.GERMANY, Locale.FRANCE);
   1029         try {
   1030             // Check that getDisplayScript() uses the default DISPLAY Locale.
   1031             assertEquals("Lateinisch", l.getDisplayScript()); // the German word for "Latin"
   1032 
   1033             assertEquals("latino", l.getDisplayScript(Locale.ITALY));
   1034 
   1035             // Fallback for navajo, a language for which we don't have data.
   1036             assertEquals("Latin", l.getDisplayScript(new Locale("nv", "US")));
   1037 
   1038             b = new Locale.Builder();
   1039             b.setLanguage("en").setRegion("US").setScript("Fooo");
   1040 
   1041             // Will be equivalent to getScriptCode for scripts that aren't
   1042             // registered with ISO-15429 (but are otherwise well formed).
   1043             l = b.build();
   1044             assertEquals("Fooo", l.getDisplayScript());
   1045         } finally {
   1046             locales.setAsDefault();
   1047         }
   1048     }
   1049 
   1050     public void test_setLanguageTag_malformedTags() {
   1051         Locale l = fromLanguageTag("a", false);
   1052         assertEquals("", l.getLanguage());
   1053         assertEquals("", l.getCountry());
   1054         assertEquals("", l.getVariant());
   1055         assertEquals("", l.getScript());
   1056 
   1057         l = fromLanguageTag("en-US-BA", false);
   1058         assertEquals("en", l.getLanguage());
   1059         assertEquals("US", l.getCountry());
   1060         assertEquals("", l.getVariant());
   1061         assertEquals("", l.getScript());
   1062 
   1063         l = fromLanguageTag("en-FOOOO-BA", false);
   1064         assertEquals("en", l.getLanguage());
   1065         assertEquals("", l.getCountry());
   1066         assertEquals("FOOOO", l.getVariant());
   1067         assertEquals("", l.getScript());
   1068 
   1069         l = fromLanguageTag("en-US-POSIX-P2", false);
   1070         assertEquals("en", l.getLanguage());
   1071         assertEquals("US", l.getCountry());
   1072         assertEquals("POSIX", l.getVariant());
   1073         assertEquals("", l.getScript());
   1074 
   1075         l = fromLanguageTag("en-Latn-US-P2", false);
   1076         assertEquals("en", l.getLanguage());
   1077         assertEquals("US", l.getCountry());
   1078         assertEquals("Latn", l.getScript());
   1079 
   1080         l = fromLanguageTag("en-f-f", false);
   1081         assertEquals("en", l.getLanguage());
   1082         assertEquals("", l.getCountry());
   1083         assertEquals("", l.getVariant());
   1084         assertEquals("", l.getScript());
   1085 
   1086         l = fromLanguageTag("en-f", false);
   1087         assertEquals("en", l.getLanguage());
   1088         assertEquals("", l.getCountry());
   1089         assertEquals("", l.getVariant());
   1090         assertEquals("", l.getScript());
   1091 
   1092         l = fromLanguageTag("en-f-fooobaaaz", false);
   1093         assertEquals("en", l.getLanguage());
   1094         assertEquals("", l.getCountry());
   1095         assertEquals("", l.getVariant());
   1096         assertEquals("", l.getScript());
   1097 
   1098         l = fromLanguageTag("en-9-baa", false);
   1099         assertEquals("en", l.getLanguage());
   1100         assertEquals("", l.getCountry());
   1101         assertEquals("", l.getVariant());
   1102         assertEquals("", l.getScript());
   1103     }
   1104 
   1105     public void test_Builder_unicodeAttributes() {
   1106         // Adding and removing attributes
   1107         Locale.Builder b = new Locale.Builder();
   1108         b.setLanguage("en");
   1109 
   1110         // Well formed attribute.
   1111         b.addUnicodeLocaleAttribute("foooo");
   1112 
   1113         try {
   1114             b.addUnicodeLocaleAttribute("fo");
   1115             fail();
   1116         } catch (IllformedLocaleException ifle) {
   1117         }
   1118 
   1119         try {
   1120             b.removeUnicodeLocaleAttribute("fo");
   1121             fail();
   1122         } catch (IllformedLocaleException ifle) {
   1123         }
   1124 
   1125         try {
   1126             b.addUnicodeLocaleAttribute("greaterthaneightchars");
   1127             fail();
   1128         } catch (IllformedLocaleException ifle) {
   1129         }
   1130 
   1131         try {
   1132             b.removeUnicodeLocaleAttribute("greaterthaneightchars");
   1133             fail();
   1134         } catch (IllformedLocaleException ifle) {
   1135         }
   1136 
   1137         try {
   1138             b.addUnicodeLocaleAttribute(null);
   1139             fail();
   1140         } catch (NullPointerException npe) {
   1141         }
   1142 
   1143         try {
   1144             b.removeUnicodeLocaleAttribute(null);
   1145             fail();
   1146         } catch (NullPointerException npe) {
   1147         }
   1148 
   1149         Locale l = b.build();
   1150         assertEquals("en-u-foooo", l.toLanguageTag());
   1151         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
   1152 
   1153         b.addUnicodeLocaleAttribute("dAtA");
   1154         l = b.build();
   1155         assertEquals("data-foooo", l.getExtension('u'));
   1156         assertTrue(l.getUnicodeLocaleAttributes().contains("data"));
   1157         assertTrue(l.getUnicodeLocaleAttributes().contains("foooo"));
   1158     }
   1159 
   1160     public void test_Builder_unicodeKeywords() {
   1161         // Adding and removing attributes
   1162         Locale.Builder b = new Locale.Builder();
   1163         b.setLanguage("en");
   1164 
   1165         // Key not of length 2.
   1166         try {
   1167             b.setUnicodeLocaleKeyword("k", "fooo");
   1168             fail();
   1169         } catch (IllformedLocaleException ifle) {
   1170         }
   1171 
   1172         // Value too short
   1173         try {
   1174             b.setUnicodeLocaleKeyword("k", "fo");
   1175             fail();
   1176         } catch (IllformedLocaleException ifle) {
   1177         }
   1178 
   1179         // Value too long
   1180         try {
   1181             b.setUnicodeLocaleKeyword("k", "foooooooo");
   1182             fail();
   1183         } catch (IllformedLocaleException ifle) {
   1184         }
   1185 
   1186 
   1187         // Null should clear the key.
   1188         b.setUnicodeLocaleKeyword("bo", "baaz");
   1189         Locale l = b.build();
   1190         assertEquals("bo-baaz", l.getExtension('u'));
   1191         assertEquals("baaz", l.getUnicodeLocaleType("bo"));
   1192 
   1193         b = new Locale.Builder();
   1194         b.setUnicodeLocaleKeyword("bo", "baaz");
   1195         b.setUnicodeLocaleKeyword("bo", null);
   1196         l = b.build();
   1197         assertNull(l.getExtension('u'));
   1198         assertNull(l.getUnicodeLocaleType("bo"));
   1199 
   1200         // When we set attributes, they should show up before extensions.
   1201         b = new Locale.Builder();
   1202         b.addUnicodeLocaleAttribute("fooo");
   1203         b.addUnicodeLocaleAttribute("gooo");
   1204         b.setUnicodeLocaleKeyword("fo", "baz");
   1205         b.setUnicodeLocaleKeyword("ka", "kaz");
   1206         l = b.build();
   1207         assertEquals("fooo-gooo-fo-baz-ka-kaz", l.getExtension('u'));
   1208         assertEquals("baz", l.getUnicodeLocaleType("fo"));
   1209         assertEquals("kaz", l.getUnicodeLocaleType("ka"));
   1210         assertTrue(l.getUnicodeLocaleAttributes().contains("fooo"));
   1211         assertTrue(l.getUnicodeLocaleAttributes().contains("gooo"));
   1212     }
   1213 
   1214     public void test_multipleExtensions() {
   1215         Locale.Builder b = new Locale.Builder();
   1216         b.setLanguage("en");
   1217         b.addUnicodeLocaleAttribute("attrib");
   1218         b.addUnicodeLocaleAttribute("attrib2");
   1219         b.setExtension('f', "fo-baaz-ga-gaaz");
   1220         b.setExtension('x', "xo-baaz-ga-gaaz");
   1221         b.setExtension('z', "zo-baaz-ga-gaaz");
   1222 
   1223         Locale l = b.build();
   1224         // Implicitly added because we added unicode locale attributes.
   1225         assertEquals("attrib-attrib2", l.getExtension('u'));
   1226         assertEquals("fo-baaz-ga-gaaz", l.getExtension('f'));
   1227         assertEquals("xo-baaz-ga-gaaz", l.getExtension('x'));
   1228         assertEquals("zo-baaz-ga-gaaz", l.getExtension('z'));
   1229     }
   1230 
   1231     public void test_immutability() {
   1232         Locale.Builder b = new Locale.Builder();
   1233         b.setExtension('g', "fooo-baaz-baar");
   1234         b.setExtension('u', "foooo-baaar-ba-baaz-ka-kaaz");
   1235 
   1236         Locale l = b.build();
   1237         try {
   1238             l.getExtensionKeys().add('g');
   1239             fail();
   1240         } catch (UnsupportedOperationException expected) {
   1241         }
   1242 
   1243         try {
   1244             l.getUnicodeLocaleAttributes().add("fooo");
   1245             fail();
   1246         } catch (UnsupportedOperationException expected) {
   1247         }
   1248     }
   1249 
   1250     public void test_lookup_noMatch() {
   1251         // RFC 4647 section 3.4.
   1252         List<LanguageRange> languageRanges = languageRangesOf(
   1253             "zh-Hant-CN-x-private1-private2",
   1254             "zh-Hant-CN-x-private1",
   1255             "zh-Hant-CN",
   1256             "zh-Hant",
   1257             "zh"
   1258         );
   1259         assertNull(Locale.lookup(languageRanges, localesOf("de-DE", "fr-FR", "ja-JP")));
   1260         assertNull(Locale.lookupTag(languageRanges, tagsOf("de-DE", "fr-FR", "ja-JP")));
   1261     }
   1262 
   1263     /**
   1264      * Tests that lookup returns the tag/locale that matches the highest priority
   1265      * LanguageRange.
   1266      */
   1267     public void test_lookup_order() {
   1268         // RFC 4647 section 3.4.
   1269         List<LanguageRange> languageRanges = languageRangesOf(
   1270             "de-Latn-DE-1996",
   1271             "zh-Hant-CN",
   1272             "de"
   1273         );
   1274 
   1275         // de would also match, but de-Latn-DE-1997 occurs earlier in the
   1276         // (sorted by descending priority) languageRanges
   1277         assertLookup("de-Latn-DE-1996",
   1278             languageRanges,
   1279             tagsOf("de", "de-Latn-DE-1996"));
   1280 
   1281         // de-Latn-DE-1996 also includes de-Latn-DE, de-Latn, de; therefore
   1282         // de-Latn-DE is preferred over zh-Hant-CN
   1283         assertLookup("de-Latn-DE",
   1284             languageRanges,
   1285             tagsOf("de", "de-Latn-DE", "de-DE-1996", "zh-Hant-CN"));
   1286 
   1287         // After reversing the priority list of the LanguageRanges, "de" now has the
   1288         // highest priority.
   1289         assertLookup("de",
   1290             languageRangesOf(
   1291                 "de",
   1292                 "zh-Hant-CN",
   1293                 "de-Latn-DE-1996"
   1294             ),
   1295             tagsOf("de", "de-Latn-DE", "de-DE-1996"));
   1296 
   1297         // Dropping "de" from the priority list of LanguageRanges false back to de-Latn-DE
   1298         assertLookup("de-Latn-DE",
   1299             languageRangesOf(
   1300                 "zh-Hant-CN",
   1301                 "de-Latn-DE-1996"
   1302             ),
   1303             tagsOf("de", "de-Latn-DE", "de-DE-1996"));
   1304     }
   1305 
   1306     public void test_lookup_nullArguments() {
   1307         List<String> tags = tagsOf("de-DE", "de-Latn-DE");
   1308         List<Locale> locales = localesOf(tags);
   1309         List<LanguageRange> languageRanges = languageRangesOf("en-*-US", "de-DE");
   1310 
   1311         assertThrowsNpe(() -> { Locale.lookup(null, locales); });
   1312         assertThrowsNpe(() -> { Locale.lookup(languageRanges, null); });
   1313 
   1314         assertThrowsNpe(() -> { Locale.lookupTag(null, tags); });
   1315         assertThrowsNpe(() -> { Locale.lookupTag(languageRanges, null); });
   1316     }
   1317 
   1318     public void test_toLanguageTag() {
   1319         Locale.Builder b = new Locale.Builder();
   1320 
   1321         // Empty builder.
   1322         Locale l = b.build();
   1323         assertEquals("und", l.toLanguageTag());
   1324 
   1325         // Only language.
   1326         b = new Locale.Builder();
   1327         b.setLanguage("en");
   1328         assertEquals("en", b.build().toLanguageTag());
   1329 
   1330         // Language & Region
   1331         b = new Locale.Builder();
   1332         b.setLanguage("en").setRegion("US");
   1333         assertEquals("en-US", b.build().toLanguageTag());
   1334 
   1335         // Language & Script
   1336         b = new Locale.Builder();
   1337         b.setLanguage("en").setScript("Latn");
   1338         assertEquals("en-Latn", b.build().toLanguageTag());
   1339 
   1340         // Language & Variant
   1341         b = new Locale.Builder();
   1342         b.setLanguage("en").setVariant("foooo");
   1343         assertEquals("en-foooo", b.build().toLanguageTag());
   1344 
   1345         // Language / script & country
   1346         b = new Locale.Builder();
   1347         b.setLanguage("en").setScript("Latn").setRegion("US");
   1348         assertEquals("en-Latn-US", b.build().toLanguageTag());
   1349 
   1350         // Language / script & variant
   1351         b = new Locale.Builder();
   1352         b.setLanguage("en").setScript("Latn").setVariant("foooo");
   1353         assertEquals("en-Latn-foooo", b.build().toLanguageTag());
   1354 
   1355         // Language / script / country / variant.
   1356         b = new Locale.Builder();
   1357         b.setLanguage("en").setScript("Latn").setVariant("foooo").setRegion("US");
   1358         assertEquals("en-Latn-US-foooo", b.build().toLanguageTag());
   1359 
   1360         // Language / extension
   1361         b = new Locale.Builder();
   1362         b.setLanguage("en").setExtension('x', "fooo-baar");
   1363         assertEquals("en-x-fooo-baar", b.build().toLanguageTag());
   1364 
   1365         // Language & multiple extensions (including unicode).
   1366         b = new Locale.Builder();
   1367         b.setLanguage("en");
   1368         b.addUnicodeLocaleAttribute("attrib");
   1369         b.addUnicodeLocaleAttribute("attrib2");
   1370         b.setExtension('f', "fo-baaz-ga-gaaz");
   1371         b.setExtension('x', "xo-baaz-ga-gaaz");
   1372         b.setExtension('z', "zo-baaz-ga-gaaz");
   1373 
   1374         l = b.build();
   1375         // Implicitly added because we added unicode locale attributes.
   1376         assertEquals("attrib-attrib2", l.getExtension('u'));
   1377         assertEquals("fo-baaz-ga-gaaz", l.getExtension('f'));
   1378         assertEquals("xo-baaz-ga-gaaz", l.getExtension('x'));
   1379         assertEquals("zo-baaz-ga-gaaz", l.getExtension('z'));
   1380 
   1381         assertEquals("en-" +
   1382                 "f-fo-baaz-ga-gaaz-" +   // extension tags in lexical order
   1383                 "u-attrib-attrib2-z-zo-baaz-ga-gaaz-" +  // unicode attribs & keywords in lex order
   1384                 "x-xo-baaz-ga-gaaz", // private use extension unmodified.
   1385                 l.toLanguageTag());
   1386     }
   1387 
   1388     public void test_toString() {
   1389         Locale.Builder b = new Locale.Builder();
   1390 
   1391         // Empty builder.
   1392         Locale l = b.build();
   1393         assertEquals("", l.toString());
   1394 
   1395         // Only language.
   1396         b = new Locale.Builder();
   1397         b.setLanguage("en");
   1398         assertEquals("en", b.build().toString());
   1399 
   1400         // Only region
   1401         b = new Locale.Builder();
   1402         b.setRegion("US");
   1403         assertEquals("_US", b.build().toString());
   1404 
   1405         // Language & Region
   1406         b = new Locale.Builder();
   1407         b.setLanguage("en").setRegion("US");
   1408         assertEquals("en_US", b.build().toString());
   1409 
   1410         // Language & Script
   1411         b = new Locale.Builder();
   1412         b.setLanguage("en").setScript("Latn");
   1413         assertEquals("en__#Latn", b.build().toString());
   1414 
   1415         // Language & Variant
   1416         b = new Locale.Builder();
   1417         b.setLanguage("en").setVariant("foooo");
   1418         assertEquals("en__foooo", b.build().toString());
   1419 
   1420         // Language / script & country
   1421         b = new Locale.Builder();
   1422         b.setLanguage("en").setScript("Latn").setRegion("US");
   1423         assertEquals("en_US_#Latn", b.build().toString());
   1424 
   1425         // Language / script & variant
   1426         b = new Locale.Builder();
   1427         b.setLanguage("en").setScript("Latn").setVariant("foooo");
   1428         assertEquals("en__foooo_#Latn", b.build().toString());
   1429 
   1430         // Language / script / country / variant.
   1431         b = new Locale.Builder();
   1432         b.setLanguage("en").setScript("Latn").setVariant("foooo").setRegion("US");
   1433         assertEquals("en_US_foooo_#Latn", b.build().toString());
   1434 
   1435         // Language / extension
   1436         b = new Locale.Builder();
   1437         b.setLanguage("en").setExtension('x', "fooo-baar");
   1438         assertEquals("en__#x-fooo-baar", b.build().toString());
   1439     }
   1440 
   1441     // Tests cases where our "guess" for the output size is incorrect.
   1442     //
   1443     // https://b.corp.google.com/issue?id=13414549
   1444     public void test_toLanguageTag_largerTag() {
   1445         Locale posix = new Locale.Builder()
   1446                 .setLanguage("en").setRegion("US").setVariant("POSIX")
   1447                 .build();
   1448         assertEquals("en-US-POSIX", posix.toLanguageTag());
   1449     }
   1450 
   1451     public void test_forLanguageTag_grandFatheredLocale() {
   1452         // Regular grandfathered locale.
   1453         Locale gaulish = Locale.forLanguageTag("cel-gaulish");
   1454         assertEquals("xtg", gaulish.getLanguage());
   1455         assertEquals("cel-gaulish", gaulish.getExtension(Locale.PRIVATE_USE_EXTENSION));
   1456         assertEquals("", gaulish.getCountry());
   1457         assertEquals("", gaulish.getScript());
   1458         assertEquals("", gaulish.getVariant());
   1459 
   1460         // Irregular grandfathered locale.
   1461         Locale enochian = Locale.forLanguageTag("i-enochian");
   1462         assertEquals("", enochian.getLanguage());
   1463         assertEquals("i-enochian", enochian.getExtension(Locale.PRIVATE_USE_EXTENSION));
   1464         assertEquals("", enochian.getCountry());
   1465         assertEquals("", enochian.getScript());
   1466         assertEquals("", enochian.getVariant());
   1467     }
   1468 
   1469     // Test case from http://b/16811867
   1470     public void testVariantsCaseSensitive() {
   1471         final Locale locale = new Locale("en", "US", "variant");
   1472         assertEquals("variant", locale.getVariant());
   1473         assertEquals(locale, Locale.forLanguageTag(locale.toLanguageTag()));
   1474     }
   1475 
   1476     public void testArabicDigits() throws Exception {
   1477         // ar-DZ uses latn digits by default, but we can override that.
   1478         Locale ar_DZ = Locale.forLanguageTag("ar-DZ");
   1479         Locale ar_DZ_arab = Locale.forLanguageTag("ar-DZ-u-nu-arab");
   1480         Locale ar_DZ_latn = Locale.forLanguageTag("ar-DZ-u-nu-latn");
   1481         assertEquals('0', new DecimalFormatSymbols(ar_DZ).getZeroDigit());
   1482         assertEquals('\u0660', new DecimalFormatSymbols(ar_DZ_arab).getZeroDigit());
   1483         assertEquals('0', new DecimalFormatSymbols(ar_DZ_latn).getZeroDigit());
   1484 
   1485         // ar-EG uses arab digits by default, but we can override that.
   1486         Locale ar_EG = Locale.forLanguageTag("ar-EG");
   1487         Locale ar_EG_arab = Locale.forLanguageTag("ar-EG-u-nu-arab");
   1488         Locale ar_EG_latn = Locale.forLanguageTag("ar-EG-u-nu-latn");
   1489         assertEquals('\u0660', new DecimalFormatSymbols(ar_EG).getZeroDigit());
   1490         assertEquals('\u0660', new DecimalFormatSymbols(ar_EG_arab).getZeroDigit());
   1491         assertEquals('0', new DecimalFormatSymbols(ar_EG_latn).getZeroDigit());
   1492     }
   1493 
   1494     public void testDefaultLocale() throws Exception {
   1495         final String userLanguage = System.getProperty("user.language", "");
   1496         final String userRegion = System.getProperty("user.region", "");
   1497         final String userLocale = System.getProperty("user.locale", "");
   1498         try {
   1499             // Assert that user.locale gets priority.
   1500             System.setUnchangeableSystemProperty("user.locale", "de-DE");
   1501             System.setUnchangeableSystemProperty("user.language", "en");
   1502             System.setUnchangeableSystemProperty("user.region", "US");
   1503 
   1504             Locale l = Locale.initDefault();
   1505             assertEquals("de", l.getLanguage());
   1506             assertEquals("DE", l.getCountry());
   1507 
   1508             // Assert that it's parsed as a full language tag.
   1509             System.setUnchangeableSystemProperty("user.locale", "de-Latn-DE");
   1510             System.setUnchangeableSystemProperty("user.language", "en");
   1511             System.setUnchangeableSystemProperty("user.region", "US");
   1512 
   1513             l = Locale.initDefault();
   1514             assertEquals("de", l.getLanguage());
   1515             assertEquals("DE", l.getCountry());
   1516             assertEquals("Latn", l.getScript());
   1517 
   1518             // Assert that we don't end up with a null default locale or an exception.
   1519             System.setUnchangeableSystemProperty("user.locale", "toolonglang-Latn-DE");
   1520 
   1521             // Note: pre-enso Locale#fromLanguageTag parser was more error-tolerant
   1522             // then the current one. Result of bad language part of tag from line above
   1523             // will be an empty Locale object.
   1524             l = Locale.initDefault();
   1525             assertEquals("", l.getLanguage());
   1526             assertEquals("", l.getCountry());
   1527         } finally {
   1528             System.setUnchangeableSystemProperty("user.language", userLanguage);
   1529             System.setUnchangeableSystemProperty("user.region", userRegion);
   1530             System.setUnchangeableSystemProperty("user.locale", userLocale);
   1531         }
   1532     }
   1533 
   1534     // http://b/20252611
   1535     public void testLegacyLocalesWithExtensions() {
   1536         Locale ja_JP_JP = new Locale("ja", "JP", "JP");
   1537         assertEquals("ca-japanese", ja_JP_JP.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
   1538         assertEquals("japanese", ja_JP_JP.getUnicodeLocaleType("ca"));
   1539 
   1540         Locale th_TH_TH = new Locale("th", "TH", "TH");
   1541         assertEquals("nu-thai", th_TH_TH.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
   1542         assertEquals("thai", th_TH_TH.getUnicodeLocaleType("nu"));
   1543     }
   1544 
   1545     // http://b/20252611
   1546     public void testLowerCaseExtensionKeys() {
   1547         // We must lowercase extension keys in forLanguageTag..
   1548         Locale ar_EG = Locale.forLanguageTag("ar-EG-U-nu-arab");
   1549         assertEquals("nu-arab", ar_EG.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
   1550         assertEquals("ar-EG-u-nu-arab", ar_EG.toLanguageTag());
   1551 
   1552         // ... and in builders.
   1553         Locale.Builder b = new Locale.Builder();
   1554         b.setLanguage("ar");
   1555         b.setRegion("EG");
   1556         b.setExtension('U', "nu-arab");
   1557         assertEquals("ar-EG-u-nu-arab", b.build().toLanguageTag());
   1558 
   1559         // Corollary : extension keys are case insensitive.
   1560         b = new Locale.Builder();
   1561         b.setLanguage("ar");
   1562         b.setRegion("EG");
   1563         b.setExtension('U', "nu-arab");
   1564         b.setExtension('u', "nu-thai");
   1565         assertEquals("ar-EG-u-nu-thai", b.build().toLanguageTag());
   1566     }
   1567 
   1568     // http://b/26387905
   1569     public void test_SerializationBug_26387905() throws Exception {
   1570         try (ObjectInputStream oinput = new ObjectInputStream(getClass()
   1571                 .getResource("/serialization/org/apache/harmony/tests/java/util/Locale_Bug_26387905.ser")
   1572                 .openStream())) {
   1573             Locale l = (Locale) oinput.readObject();
   1574         }
   1575     }
   1576 
   1577     public void test_setDefault_withCategory() {
   1578         final Locale defaultLocale = Locale.getDefault();
   1579         try {
   1580             // Establish a baseline for the checks further down
   1581             Locale.setDefault(Locale.US);
   1582             assertEquals(Locale.US, Locale.getDefault(Locale.Category.FORMAT));
   1583             assertEquals(Locale.US, Locale.getDefault(Locale.Category.DISPLAY));
   1584             assertEquals(Locale.US, Locale.getDefault());
   1585 
   1586             Locale.setDefault(Locale.Category.FORMAT, Locale.UK);
   1587             assertEquals(Locale.UK, Locale.getDefault(Locale.Category.FORMAT));
   1588             assertEquals(Locale.US, Locale.getDefault(Locale.Category.DISPLAY));
   1589             assertEquals(Locale.US, Locale.getDefault());
   1590 
   1591             Locale.setDefault(Locale.Category.DISPLAY, Locale.CANADA);
   1592             assertEquals(Locale.UK, Locale.getDefault(Locale.Category.FORMAT));
   1593             assertEquals(Locale.CANADA, Locale.getDefault(Locale.Category.DISPLAY));
   1594             assertEquals(Locale.US, Locale.getDefault());
   1595 
   1596             Locale.setDefault(Locale.FRANCE);
   1597             assertEquals(Locale.FRANCE, Locale.getDefault(Locale.Category.FORMAT));
   1598             assertEquals(Locale.FRANCE, Locale.getDefault(Locale.Category.DISPLAY));
   1599             assertEquals(Locale.FRANCE, Locale.getDefault());
   1600 
   1601             // Check that setDefault(Locale) sets all three defaults
   1602             Locale.setDefault(Locale.US);
   1603             assertEquals(Locale.US, Locale.getDefault(Locale.Category.FORMAT));
   1604             assertEquals(Locale.US, Locale.getDefault(Locale.Category.DISPLAY));
   1605             assertEquals(Locale.US, Locale.getDefault());
   1606         } finally {
   1607             Locale.setDefault(defaultLocale);
   1608         }
   1609     }
   1610 
   1611     private static List<Locale> localesOf(String... languageTags) {
   1612         return localesOf(tagsOf(languageTags));
   1613     }
   1614 
   1615     private static List<Locale> localesOf(List<String> languageTags) {
   1616         List<Locale> result = new ArrayList<>();
   1617         for (String languageTag : languageTags) {
   1618             result.add(Locale.forLanguageTag(languageTag));
   1619         }
   1620         return Collections.unmodifiableList(result);
   1621     }
   1622 
   1623     private static List<String> tagsOf(String... tags) {
   1624         List<String> result = new ArrayList<>();
   1625         for (String tag : tags) {
   1626             result.add(tag.toLowerCase());
   1627         }
   1628         return Collections.unmodifiableList(result);
   1629     }
   1630 
   1631     private static List<LanguageRange> languageRangesOf(String... languageRanges) {
   1632         List<LanguageRange> result = new ArrayList<>();
   1633         for (String languageRange : languageRanges) {
   1634             result.add(new LanguageRange(languageRange));
   1635         }
   1636         return Collections.unmodifiableList(result);
   1637     }
   1638 
   1639     private static void assertFilter(List<String> filteredTags, List<LanguageRange> languageRanges,
   1640         List<String> tags) {
   1641         assertEquals(filteredTags, Locale.filterTags(languageRanges, tags));
   1642 
   1643         List<Locale> locales = localesOf(tags);
   1644         List<Locale> filteredLocales = localesOf(filteredTags);
   1645         assertEquals(filteredLocales, Locale.filter(languageRanges, locales));
   1646     }
   1647 
   1648     private static void assertFilter(List<String> filteredTags, List<LanguageRange> languageRanges,
   1649         List<String> tags, Locale.FilteringMode filteringMode) {
   1650         assertEquals(filteredTags,
   1651             Locale.filterTags(languageRanges, tags, filteringMode));
   1652 
   1653         List<Locale> locales = localesOf(tags);
   1654         List<Locale> filteredLocales = localesOf(filteredTags);
   1655         assertEquals(filteredLocales, Locale.filter(languageRanges, locales, filteringMode));
   1656     }
   1657 
   1658     private static void assertThrowsNpe(Runnable runnable) {
   1659         try {
   1660             runnable.run();
   1661             fail("Should have thrown NullPointerException");
   1662         } catch (NullPointerException expected) {
   1663         }
   1664     }
   1665 
   1666     private static void assertLookup(String expectedTag, List<LanguageRange> languageRanges,
   1667         List<String> tags) {
   1668         assertEquals(expectedTag.toLowerCase(), Locale.lookupTag(languageRanges, tags));
   1669 
   1670         assertEquals(Locale.forLanguageTag(expectedTag),
   1671             Locale.lookup(languageRanges, localesOf(tags)));
   1672     }
   1673 
   1674 }
   1675