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