1 /* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import java.io.BufferedReader; 27 import java.io.ByteArrayInputStream; 28 import java.io.ByteArrayOutputStream; 29 import java.io.File; 30 import java.io.FileInputStream; 31 import java.io.InputStreamReader; 32 import java.io.ObjectInputStream; 33 import java.io.ObjectOutputStream; 34 import java.net.URISyntaxException; 35 import java.net.URL; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.IllformedLocaleException; 39 import java.util.List; 40 import java.util.Locale; 41 import java.util.Locale.Builder; 42 import java.util.Set; 43 44 /** 45 * @test 46 * @bug 6875847 6992272 7002320 7015500 7023613 47 * @summary test API changes to Locale 48 */ 49 public class LocaleEnhanceTest extends LocaleTestFmwk { 50 51 public static void main(String[] args) throws Exception { 52 List<String> argList = new ArrayList<String>(); 53 argList.addAll(Arrays.asList(args)); 54 argList.add("-nothrow"); 55 new LocaleEnhanceTest().run(argList.toArray(new String[argList.size()])); 56 } 57 58 public LocaleEnhanceTest() { 59 } 60 61 /// 62 /// Generic sanity tests 63 /// 64 65 /** A canonical language code. */ 66 private static final String l = "en"; 67 68 /** A canonical script code.. */ 69 private static final String s = "Latn"; 70 71 /** A canonical region code. */ 72 private static final String c = "US"; 73 74 /** A canonical variant code. */ 75 private static final String v = "NewYork"; 76 77 /** 78 * Ensure that Builder builds locales that have the expected 79 * tag and java6 ID. Note the odd cases for the ID. 80 */ 81 public void testCreateLocaleCanonicalValid() { 82 String[] valids = { 83 "en-Latn-US-NewYork", "en_US_NewYork_#Latn", 84 "en-Latn-US", "en_US_#Latn", 85 "en-Latn-NewYork", "en__NewYork_#Latn", // double underscore 86 "en-Latn", "en__#Latn", // double underscore 87 "en-US-NewYork", "en_US_NewYork", 88 "en-US", "en_US", 89 "en-NewYork", "en__NewYork", // double underscore 90 "en", "en", 91 "und-Latn-US-NewYork", "_US_NewYork_#Latn", 92 "und-Latn-US", "_US_#Latn", 93 "und-Latn-NewYork", "", // variant only not supported 94 "und-Latn", "", 95 "und-US-NewYork", "_US_NewYork", 96 "und-US", "_US", 97 "und-NewYork", "", // variant only not supported 98 "und", "" 99 }; 100 101 Builder builder = new Builder(); 102 103 for (int i = 0; i < valids.length; i += 2) { 104 String tag = valids[i]; 105 String id = valids[i+1]; 106 107 String idl = (i & 16) == 0 ? l : ""; 108 String ids = (i & 8) == 0 ? s : ""; 109 String idc = (i & 4) == 0 ? c : ""; 110 String idv = (i & 2) == 0 ? v : ""; 111 112 String msg = String.valueOf(i/2) + ": '" + tag + "' "; 113 114 try { 115 Locale l = builder 116 .setLanguage(idl) 117 .setScript(ids) 118 .setRegion(idc) 119 .setVariant(idv) 120 .build(); 121 assertEquals(msg + "language", idl, l.getLanguage()); 122 assertEquals(msg + "script", ids, l.getScript()); 123 assertEquals(msg + "country", idc, l.getCountry()); 124 assertEquals(msg + "variant", idv, l.getVariant()); 125 assertEquals(msg + "tag", tag, l.toLanguageTag()); 126 assertEquals(msg + "id", id, l.toString()); 127 } 128 catch (IllegalArgumentException e) { 129 errln(msg + e.getMessage()); 130 } 131 } 132 } 133 134 /** 135 * Test that locale construction works with 'multiple variants'. 136 * <p> 137 * The string "Newer__Yorker" is treated as three subtags, 138 * "Newer", "", and "Yorker", and concatenated into one 139 * subtag by omitting empty subtags and joining the remainer 140 * with underscores. So the resulting variant tag is "Newer_Yorker". 141 * Note that 'New' and 'York' are invalid BCP47 variant subtags 142 * because they are too short. 143 */ 144 public void testCreateLocaleMultipleVariants() { 145 146 String[] valids = { 147 "en-Latn-US-Newer-Yorker", "en_US_Newer_Yorker_#Latn", 148 "en-Latn-Newer-Yorker", "en__Newer_Yorker_#Latn", 149 "en-US-Newer-Yorker", "en_US_Newer_Yorker", 150 "en-Newer-Yorker", "en__Newer_Yorker", 151 "und-Latn-US-Newer-Yorker", "_US_Newer_Yorker_#Latn", 152 "und-Latn-Newer-Yorker", "", 153 "und-US-Newer-Yorker", "_US_Newer_Yorker", 154 "und-Newer-Yorker", "", 155 }; 156 157 Builder builder = new Builder(); // lenient variant 158 159 final String idv = "Newer_Yorker"; 160 for (int i = 0; i < valids.length; i += 2) { 161 String tag = valids[i]; 162 String id = valids[i+1]; 163 164 String idl = (i & 8) == 0 ? l : ""; 165 String ids = (i & 4) == 0 ? s : ""; 166 String idc = (i & 2) == 0 ? c : ""; 167 168 String msg = String.valueOf(i/2) + ": " + tag + " "; 169 try { 170 Locale l = builder 171 .setLanguage(idl) 172 .setScript(ids) 173 .setRegion(idc) 174 .setVariant(idv) 175 .build(); 176 177 assertEquals(msg + " language", idl, l.getLanguage()); 178 assertEquals(msg + " script", ids, l.getScript()); 179 assertEquals(msg + " country", idc, l.getCountry()); 180 assertEquals(msg + " variant", idv, l.getVariant()); 181 182 assertEquals(msg + "tag", tag, l.toLanguageTag()); 183 assertEquals(msg + "id", id, l.toString()); 184 } 185 catch (IllegalArgumentException e) { 186 errln(msg + e.getMessage()); 187 } 188 } 189 } 190 191 /** 192 * Ensure that all these invalid formats are not recognized by 193 * forLanguageTag. 194 */ 195 public void testCreateLocaleCanonicalInvalidSeparator() { 196 String[] invalids = { 197 // trailing separator 198 "en_Latn_US_NewYork_", 199 "en_Latn_US_", 200 "en_Latn_", 201 "en_", 202 "_", 203 204 // double separator 205 "en_Latn_US__NewYork", 206 "_Latn_US__NewYork", 207 "en_US__NewYork", 208 "_US__NewYork", 209 210 // are these OK? 211 // "en_Latn__US_NewYork", // variant is 'US_NewYork' 212 // "_Latn__US_NewYork", // variant is 'US_NewYork' 213 // "en__Latn_US_NewYork", // variant is 'Latn_US_NewYork' 214 // "en__US_NewYork", // variant is 'US_NewYork' 215 216 // double separator without language or script 217 "__US", 218 "__NewYork", 219 220 // triple separator anywhere except within variant 221 "en___NewYork", 222 "en_Latn___NewYork", 223 "_Latn___NewYork", 224 "___NewYork", 225 }; 226 227 for (int i = 0; i < invalids.length; ++i) { 228 String id = invalids[i]; 229 Locale l = Locale.forLanguageTag(id); 230 assertEquals(id, "und", l.toLanguageTag()); 231 } 232 } 233 234 /** 235 * Ensure that all current locale ids parse. Use DateFormat as a proxy 236 * for all current locale ids. 237 */ 238 public void testCurrentLocales() { 239 Locale[] locales = java.text.DateFormat.getAvailableLocales(); 240 Builder builder = new Builder(); 241 242 for (Locale target : locales) { 243 String tag = target.toLanguageTag(); 244 245 // the tag recreates the original locale, 246 // except no_NO_NY 247 Locale tagResult = Locale.forLanguageTag(tag); 248 if (!target.getVariant().equals("NY")) { 249 assertEquals("tagResult", target, tagResult); 250 } 251 252 // the builder also recreates the original locale, 253 // except ja_JP_JP, th_TH_TH and no_NO_NY 254 Locale builderResult = builder.setLocale(target).build(); 255 if (target.getVariant().length() != 2) { 256 assertEquals("builderResult", target, builderResult); 257 } 258 } 259 } 260 261 /** 262 * Ensure that all icu locale ids parse. 263 */ 264 public void testIcuLocales() throws Exception { 265 BufferedReader br = new BufferedReader( 266 new InputStreamReader( 267 LocaleEnhanceTest.class.getResourceAsStream("icuLocales.txt"), 268 "UTF-8")); 269 String id = null; 270 while (null != (id = br.readLine())) { 271 Locale result = Locale.forLanguageTag(id); 272 assertEquals("ulocale", id, result.toLanguageTag()); 273 } 274 } 275 276 /// 277 /// Compatibility tests 278 /// 279 280 public void testConstructor() { 281 // all the old weirdness still holds, no new weirdness 282 String[][] tests = { 283 // language to lower case, region to upper, variant unchanged 284 // short 285 { "X", "y", "z", "x", "Y" }, 286 // long 287 { "xXxXxXxXxXxX", "yYyYyYyYyYyYyYyY", "zZzZzZzZzZzZzZzZ", 288 "xxxxxxxxxxxx", "YYYYYYYYYYYYYYYY" }, 289 // mapped language ids 290 { "he", "IW", "", "iw" }, 291 { "iw", "IW", "", "iw" }, 292 { "yi", "DE", "", "ji" }, 293 { "ji", "DE", "", "ji" }, 294 { "id", "ID", "", "in" }, 295 { "in", "ID", "", "in" }, 296 // special variants 297 { "ja", "JP", "JP" }, 298 { "th", "TH", "TH" }, 299 { "no", "NO", "NY" }, 300 { "no", "NO", "NY" }, 301 // no canonicalization of 3-letter language codes 302 { "eng", "US", "" } 303 }; 304 for (int i = 0; i < tests.length; ++ i) { 305 String[] test = tests[i]; 306 String id = String.valueOf(i); 307 Locale locale = new Locale(test[0], test[1], test[2]); 308 assertEquals(id + " lang", test.length > 3 ? test[3] : test[0], locale.getLanguage()); 309 assertEquals(id + " region", test.length > 4 ? test[4] : test[1], locale.getCountry()); 310 assertEquals(id + " variant", test.length > 5 ? test[5] : test[2], locale.getVariant()); 311 } 312 } 313 314 /// 315 /// Locale API tests. 316 /// 317 318 public void testGetScript() { 319 // forLanguageTag normalizes case 320 Locale locale = Locale.forLanguageTag("und-latn"); 321 assertEquals("forLanguageTag", "Latn", locale.getScript()); 322 323 // Builder normalizes case 324 locale = new Builder().setScript("LATN").build(); 325 assertEquals("builder", "Latn", locale.getScript()); 326 327 // empty string is returned, not null, if there is no script 328 locale = Locale.forLanguageTag("und"); 329 assertEquals("script is empty string", "", locale.getScript()); 330 } 331 332 public void testGetExtension() { 333 // forLanguageTag does NOT normalize to hyphen 334 Locale locale = Locale.forLanguageTag("und-a-some_ex-tension"); 335 assertEquals("some_ex-tension", null, locale.getExtension('a')); 336 337 // regular extension 338 locale = new Builder().setExtension('a', "some-ex-tension").build(); 339 assertEquals("builder", "some-ex-tension", locale.getExtension('a')); 340 341 // returns null if extension is not present 342 assertEquals("empty b", null, locale.getExtension('b')); 343 344 // throws exception if extension tag is illegal 345 new ExpectIAE() { public void call() { Locale.forLanguageTag("").getExtension('\uD800'); }}; 346 347 // 'x' is not an extension, it's a private use tag, but it's accessed through this API 348 locale = Locale.forLanguageTag("x-y-z-blork"); 349 assertEquals("x", "y-z-blork", locale.getExtension('x')); 350 } 351 352 public void testGetExtensionKeys() { 353 Locale locale = Locale.forLanguageTag("und-a-xx-yy-b-zz-ww"); 354 Set<Character> result = locale.getExtensionKeys(); 355 assertEquals("result size", 2, result.size()); 356 assertTrue("'a','b'", result.contains('a') && result.contains('b')); 357 358 // result is not mutable 359 try { 360 result.add('x'); 361 errln("expected exception on add to extension key set"); 362 } 363 catch (UnsupportedOperationException e) { 364 // ok 365 } 366 367 // returns empty set if no extensions 368 locale = Locale.forLanguageTag("und"); 369 assertTrue("empty result", locale.getExtensionKeys().isEmpty()); 370 } 371 372 public void testGetUnicodeLocaleAttributes() { 373 Locale locale = Locale.forLanguageTag("en-US-u-abc-def"); 374 Set<String> attributes = locale.getUnicodeLocaleAttributes(); 375 assertEquals("number of attributes", 2, attributes.size()); 376 assertTrue("attribute abc", attributes.contains("abc")); 377 assertTrue("attribute def", attributes.contains("def")); 378 379 locale = Locale.forLanguageTag("en-US-u-ca-gregory"); 380 attributes = locale.getUnicodeLocaleAttributes(); 381 assertTrue("empty attributes", attributes.isEmpty()); 382 } 383 384 public void testGetUnicodeLocaleType() { 385 Locale locale = Locale.forLanguageTag("und-u-co-japanese-nu-thai"); 386 assertEquals("collation", "japanese", locale.getUnicodeLocaleType("co")); 387 assertEquals("numbers", "thai", locale.getUnicodeLocaleType("nu")); 388 389 // Unicode locale extension key is case insensitive 390 assertEquals("key case", "japanese", locale.getUnicodeLocaleType("Co")); 391 392 // if keyword is not present, returns null 393 assertEquals("locale keyword not present", null, locale.getUnicodeLocaleType("xx")); 394 395 // if no locale extension is set, returns null 396 locale = Locale.forLanguageTag("und"); 397 assertEquals("locale extension not present", null, locale.getUnicodeLocaleType("co")); 398 399 // typeless keyword 400 locale = Locale.forLanguageTag("und-u-kn"); 401 assertEquals("typeless keyword", "", locale.getUnicodeLocaleType("kn")); 402 403 // invalid keys throw exception 404 new ExpectIAE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType("q"); }}; 405 new ExpectIAE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType("abcdefghi"); }}; 406 407 // null argument throws exception 408 new ExpectNPE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType(null); }}; 409 } 410 411 public void testGetUnicodeLocaleKeys() { 412 Locale locale = Locale.forLanguageTag("und-u-co-japanese-nu-thai"); 413 Set<String> result = locale.getUnicodeLocaleKeys(); 414 assertEquals("two keys", 2, result.size()); 415 assertTrue("co and nu", result.contains("co") && result.contains("nu")); 416 417 // result is not modifiable 418 try { 419 result.add("frobozz"); 420 errln("expected exception when add to locale key set"); 421 } 422 catch (UnsupportedOperationException e) { 423 // ok 424 } 425 } 426 427 public void testPrivateUseExtension() { 428 Locale locale = Locale.forLanguageTag("x-y-x-blork-"); 429 assertEquals("blork", "y-x-blork", locale.getExtension(Locale.PRIVATE_USE_EXTENSION)); 430 431 locale = Locale.forLanguageTag("und"); 432 assertEquals("no privateuse", null, locale.getExtension(Locale.PRIVATE_USE_EXTENSION)); 433 } 434 435 public void testToLanguageTag() { 436 // lots of normalization to test here 437 // test locales created using the constructor 438 String[][] tests = { 439 // empty locale canonicalizes to 'und' 440 { "", "", "", "und" }, 441 // variant alone is not a valid Locale, but has a valid language tag 442 { "", "", "NewYork", "und-NewYork" }, 443 // standard valid locales 444 { "", "Us", "", "und-US" }, 445 { "", "US", "NewYork", "und-US-NewYork" }, 446 { "EN", "", "", "en" }, 447 { "EN", "", "NewYork", "en-NewYork" }, 448 { "EN", "US", "", "en-US" }, 449 { "EN", "US", "NewYork", "en-US-NewYork" }, 450 // underscore in variant will be emitted as multiple variant subtags 451 { "en", "US", "Newer_Yorker", "en-US-Newer-Yorker" }, 452 // invalid variant subtags are appended as private use 453 { "en", "US", "new_yorker", "en-US-x-lvariant-new-yorker" }, 454 // the first invalid variant subtags and following variant subtags are appended as private use 455 { "en", "US", "Windows_XP_Home", "en-US-Windows-x-lvariant-XP-Home" }, 456 // too long variant and following variant subtags disappear 457 { "en", "US", "WindowsVista_SP2", "en-US" }, 458 // invalid region subtag disappears 459 { "en", "USA", "", "en" }, 460 // invalid language tag disappears 461 { "e", "US", "", "und-US" }, 462 // three-letter language tags are not canonicalized 463 { "Eng", "", "", "eng" }, 464 // legacy languages canonicalize to modern equivalents 465 { "he", "IW", "", "he-IW" }, 466 { "iw", "IW", "", "he-IW" }, 467 { "yi", "DE", "", "yi-DE" }, 468 { "ji", "DE", "", "yi-DE" }, 469 { "id", "ID", "", "id-ID" }, 470 { "in", "ID", "", "id-ID" }, 471 // special values are converted on output 472 { "ja", "JP", "JP", "ja-JP-u-ca-japanese-x-lvariant-JP" }, 473 { "th", "TH", "TH", "th-TH-u-nu-thai-x-lvariant-TH" }, 474 { "no", "NO", "NY", "nn-NO" } 475 }; 476 for (int i = 0; i < tests.length; ++i) { 477 String[] test = tests[i]; 478 Locale locale = new Locale(test[0], test[1], test[2]); 479 assertEquals("case " + i, test[3], locale.toLanguageTag()); 480 } 481 482 // test locales created from forLanguageTag 483 String[][] tests1 = { 484 // case is normalized during the round trip 485 { "EN-us", "en-US" }, 486 { "en-Latn-US", "en-Latn-US" }, 487 // reordering Unicode locale extensions 488 { "de-u-co-phonebk-ca-gregory", "de-u-ca-gregory-co-phonebk" }, 489 // private use only language tag is preserved (no extra "und") 490 { "x-elmer", "x-elmer" }, 491 { "x-lvariant-JP", "x-lvariant-JP" }, 492 }; 493 for (String[] test : tests1) { 494 Locale locale = Locale.forLanguageTag(test[0]); 495 assertEquals("case " + test[0], test[1], locale.toLanguageTag()); 496 } 497 498 } 499 500 public void testForLanguageTag() { 501 // forLanguageTag implements the 'Language-Tag' production of 502 // BCP47, so it handles private use and grandfathered tags, 503 // unlike locale builder. Tags listed below (except for the 504 // sample private use tags) come from 4646bis Feb 29, 2009. 505 506 String[][] tests = { 507 // private use tags only 508 { "x-abc", "x-abc" }, 509 { "x-a-b-c", "x-a-b-c" }, 510 { "x-a-12345678", "x-a-12345678" }, 511 512 // grandfathered tags with preferred mappings 513 { "i-ami", "ami" }, 514 { "i-bnn", "bnn" }, 515 { "i-hak", "hak" }, 516 { "i-klingon", "tlh" }, 517 { "i-lux", "lb" }, // two-letter tag 518 { "i-navajo", "nv" }, // two-letter tag 519 { "i-pwn", "pwn" }, 520 { "i-tao", "tao" }, 521 { "i-tay", "tay" }, 522 { "i-tsu", "tsu" }, 523 { "art-lojban", "jbo" }, 524 { "no-bok", "nb" }, 525 { "no-nyn", "nn" }, 526 { "sgn-BE-FR", "sfb" }, 527 { "sgn-BE-NL", "vgt" }, 528 { "sgn-CH-DE", "sgg" }, 529 { "zh-guoyu", "cmn" }, 530 { "zh-hakka", "hak" }, 531 { "zh-min-nan", "nan" }, 532 { "zh-xiang", "hsn" }, 533 534 // grandfathered irregular tags, no preferred mappings, drop illegal fields 535 // from end. If no subtag is mappable, fallback to 'und' 536 { "i-default", "en-x-i-default" }, 537 { "i-enochian", "x-i-enochian" }, 538 { "i-mingo", "see-x-i-mingo" }, 539 { "en-GB-oed", "en-GB-x-oed" }, 540 { "zh-min", "nan-x-zh-min" }, 541 { "cel-gaulish", "xtg-x-cel-gaulish" }, 542 }; 543 for (int i = 0; i < tests.length; ++i) { 544 String[] test = tests[i]; 545 Locale locale = Locale.forLanguageTag(test[0]); 546 assertEquals("grandfathered case " + i, test[1], locale.toLanguageTag()); 547 } 548 549 // forLanguageTag ignores everything past the first place it encounters 550 // a syntax error 551 tests = new String[][] { 552 { "valid", 553 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-12345678-z", 554 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-12345678-z" }, 555 { "segment of private use tag too long", 556 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-123456789-z", 557 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y" }, 558 { "segment of private use tag is empty", 559 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y--12345678-z", 560 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y" }, 561 { "first segment of private use tag is empty", 562 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x--y-12345678-z", 563 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def" }, 564 { "illegal extension tag", 565 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-\uD800-y-12345678-z", 566 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def" }, 567 { "locale subtag with no value", 568 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-x-y-12345678-z", 569 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-x-y-12345678-z" }, 570 { "locale key subtag invalid", 571 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-123456789-def-x-y-12345678-z", 572 "en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc" }, 573 // locale key subtag invalid in earlier position, all following subtags 574 // dropped (and so the locale extension dropped as well) 575 { "locale key subtag invalid in earlier position", 576 "en-US-Newer-Yorker-a-bb-cc-dd-u-123456789-abc-bb-def-x-y-12345678-z", 577 "en-US-Newer-Yorker-a-bb-cc-dd" }, 578 }; 579 for (int i = 0; i < tests.length; ++i) { 580 String[] test = tests[i]; 581 String msg = "syntax error case " + i + " " + test[0]; 582 try { 583 Locale locale = Locale.forLanguageTag(test[1]); 584 assertEquals(msg, test[2], locale.toLanguageTag()); 585 } 586 catch (IllegalArgumentException e) { 587 errln(msg + " caught exception: " + e); 588 } 589 } 590 591 // duplicated extension are just ignored 592 Locale locale = Locale.forLanguageTag("und-d-aa-00-bb-01-D-AA-10-cc-11-c-1234"); 593 assertEquals("extension", "aa-00-bb-01", locale.getExtension('d')); 594 assertEquals("extension c", "1234", locale.getExtension('c')); 595 596 // redundant Unicode locale keys in an extension are ignored 597 locale = Locale.forLanguageTag("und-u-aa-000-bb-001-bB-002-cc-003-c-1234"); 598 assertEquals("Unicode keywords", "aa-000-bb-001-cc-003", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION)); 599 assertEquals("Duplicated Unicode locake key followed by an extension", "1234", locale.getExtension('c')); 600 } 601 602 public void testGetDisplayScript() { 603 Locale latnLocale = Locale.forLanguageTag("und-latn"); 604 Locale hansLocale = Locale.forLanguageTag("und-hans"); 605 606 Locale oldLocale = Locale.getDefault(); 607 608 Locale.setDefault(Locale.US); 609 assertEquals("latn US", "Latin", latnLocale.getDisplayScript()); 610 assertEquals("hans US", "Simplified Han", hansLocale.getDisplayScript()); 611 612 // note, no localization data yet other than US 613 // this should break when we have localization data for DE 614 Locale.setDefault(Locale.GERMANY); 615 assertEquals("latn DE", "Latin", latnLocale.getDisplayScript()); 616 assertEquals("hans DE", "Simplified Han", hansLocale.getDisplayScript()); 617 618 Locale.setDefault(oldLocale); 619 } 620 621 public void testGetDisplayScriptWithLocale() { 622 Locale latnLocale = Locale.forLanguageTag("und-latn"); 623 Locale hansLocale = Locale.forLanguageTag("und-hans"); 624 625 assertEquals("latn US", "Latin", latnLocale.getDisplayScript(Locale.US)); 626 assertEquals("hans US", "Simplified Han", hansLocale.getDisplayScript(Locale.US)); 627 628 // note, no localization data yet other than US 629 // this should break when we have localization data for DE 630 assertEquals("latn DE", "Latin", latnLocale.getDisplayScript(Locale.GERMANY)); 631 assertEquals("hans DE", "Simplified Han", hansLocale.getDisplayScript(Locale.GERMANY)); 632 } 633 634 public void testGetDisplayName() { 635 final Locale[] testLocales = { 636 Locale.ROOT, 637 new Locale("en"), 638 new Locale("en", "US"), 639 new Locale("", "US"), 640 new Locale("no", "NO", "NY"), 641 new Locale("", "", "NY"), 642 Locale.forLanguageTag("zh-Hans"), 643 Locale.forLanguageTag("zh-Hant"), 644 Locale.forLanguageTag("zh-Hans-CN"), 645 Locale.forLanguageTag("und-Hans"), 646 }; 647 648 final String[] displayNameEnglish = { 649 "", 650 "English", 651 "English (United States)", 652 "United States", 653 "Norwegian (Norway,Nynorsk)", 654 "Nynorsk", 655 "Chinese (Simplified Han)", 656 "Chinese (Traditional Han)", 657 "Chinese (Simplified Han,China)", 658 "Simplified Han", 659 }; 660 661 final String[] displayNameSimplifiedChinese = { 662 "", 663 "\u82f1\u6587", 664 "\u82f1\u6587 (\u7f8e\u56fd)", 665 "\u7f8e\u56fd", 666 "\u632a\u5a01\u6587 (\u632a\u5a01,Nynorsk)", 667 "Nynorsk", 668 "\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587)", 669 "\u4e2d\u6587 (\u7e41\u4f53\u4e2d\u6587)", 670 "\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587,\u4e2d\u56fd)", 671 "\u7b80\u4f53\u4e2d\u6587", 672 }; 673 674 for (int i = 0; i < testLocales.length; i++) { 675 Locale loc = testLocales[i]; 676 assertEquals("English display name for " + loc.toLanguageTag(), 677 displayNameEnglish[i], loc.getDisplayName(Locale.ENGLISH)); 678 assertEquals("Simplified Chinese display name for " + loc.toLanguageTag(), 679 displayNameSimplifiedChinese[i], loc.getDisplayName(Locale.CHINA)); 680 } 681 } 682 683 /// 684 /// Builder tests 685 /// 686 687 public void testBuilderSetLocale() { 688 Builder builder = new Builder(); 689 Builder lenientBuilder = new Builder(); 690 691 String languageTag = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z"; 692 String target = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z"; 693 694 Locale locale = Locale.forLanguageTag(languageTag); 695 Locale result = lenientBuilder 696 .setLocale(locale) 697 .build(); 698 assertEquals("long tag", target, result.toLanguageTag()); 699 assertEquals("long tag", locale, result); 700 701 // null is illegal 702 new BuilderNPE("locale") { 703 public void call() { b.setLocale(null); } 704 }; 705 706 // builder canonicalizes the three legacy locales: 707 // ja_JP_JP, th_TH_TH, no_NY_NO. 708 locale = builder.setLocale(new Locale("ja", "JP", "JP")).build(); 709 assertEquals("ja_JP_JP languagetag", "ja-JP-u-ca-japanese", locale.toLanguageTag()); 710 assertEquals("ja_JP_JP variant", "", locale.getVariant()); 711 712 locale = builder.setLocale(new Locale("th", "TH", "TH")).build(); 713 assertEquals("th_TH_TH languagetag", "th-TH-u-nu-thai", locale.toLanguageTag()); 714 assertEquals("th_TH_TH variant", "", locale.getVariant()); 715 716 locale = builder.setLocale(new Locale("no", "NO", "NY")).build(); 717 assertEquals("no_NO_NY languagetag", "nn-NO", locale.toLanguageTag()); 718 assertEquals("no_NO_NY language", "nn", locale.getLanguage()); 719 assertEquals("no_NO_NY variant", "", locale.getVariant()); 720 721 // non-canonical, non-legacy locales are invalid 722 new BuilderILE("123_4567_89") { 723 public void call() { 724 b.setLocale(new Locale("123", "4567", "89")); 725 } 726 }; 727 } 728 729 public void testBuilderSetLanguageTag() { 730 String source = "eN-LaTn-Us-NewYork-A-Xx-B-Yy-X-1-2-3"; 731 String target = "en-Latn-US-NewYork-a-xx-b-yy-x-1-2-3"; 732 Builder builder = new Builder(); 733 String result = builder 734 .setLanguageTag(source) 735 .build() 736 .toLanguageTag(); 737 assertEquals("language", target, result); 738 739 // redundant extensions cause a failure 740 new BuilderILE() { public void call() { b.setLanguageTag("und-a-xx-yy-b-ww-A-00-11-c-vv"); }}; 741 742 // redundant Unicode locale extension keys within an Unicode locale extension cause a failure 743 new BuilderILE() { public void call() { b.setLanguageTag("und-u-nu-thai-NU-chinese-xx-1234"); }}; 744 } 745 746 public void testBuilderSetLanguage() { 747 // language is normalized to lower case 748 String source = "eN"; 749 String target = "en"; 750 String defaulted = ""; 751 Builder builder = new Builder(); 752 String result = builder 753 .setLanguage(source) 754 .build() 755 .getLanguage(); 756 assertEquals("en", target, result); 757 758 // setting with empty resets 759 result = builder 760 .setLanguage(target) 761 .setLanguage("") 762 .build() 763 .getLanguage(); 764 assertEquals("empty", defaulted, result); 765 766 // setting with null resets too 767 result = builder 768 .setLanguage(target) 769 .setLanguage(null) 770 .build() 771 .getLanguage(); 772 assertEquals("null", defaulted, result); 773 774 // language codes must be 2-8 alpha 775 // for forwards compatibility, 4-alpha and 5-8 alpha (registered) 776 // languages are accepted syntax 777 new BuilderILE("q", "abcdefghi", "13") { public void call() { b.setLanguage(arg); }}; 778 779 // language code validation is NOT performed, any 2-8-alpha passes 780 assertNotNull("2alpha", builder.setLanguage("zz").build()); 781 assertNotNull("8alpha", builder.setLanguage("abcdefgh").build()); 782 783 // three-letter language codes are NOT canonicalized to two-letter 784 result = builder 785 .setLanguage("eng") 786 .build() 787 .getLanguage(); 788 assertEquals("eng", "eng", result); 789 } 790 791 public void testBuilderSetScript() { 792 // script is normalized to title case 793 String source = "lAtN"; 794 String target = "Latn"; 795 String defaulted = ""; 796 Builder builder = new Builder(); 797 String result = builder 798 .setScript(source) 799 .build() 800 .getScript(); 801 assertEquals("script", target, result); 802 803 // setting with empty resets 804 result = builder 805 .setScript(target) 806 .setScript("") 807 .build() 808 .getScript(); 809 assertEquals("empty", defaulted, result); 810 811 // settting with null also resets 812 result = builder 813 .setScript(target) 814 .setScript(null) 815 .build() 816 .getScript(); 817 assertEquals("null", defaulted, result); 818 819 // ill-formed script codes throw IAE 820 // must be 4alpha 821 new BuilderILE("abc", "abcde", "l3tn") { public void call() { b.setScript(arg); }}; 822 823 // script code validation is NOT performed, any 4-alpha passes 824 assertEquals("4alpha", "Wxyz", builder.setScript("wxyz").build().getScript()); 825 } 826 827 public void testBuilderSetRegion() { 828 // region is normalized to upper case 829 String source = "uS"; 830 String target = "US"; 831 String defaulted = ""; 832 Builder builder = new Builder(); 833 String result = builder 834 .setRegion(source) 835 .build() 836 .getCountry(); 837 assertEquals("us", target, result); 838 839 // setting with empty resets 840 result = builder 841 .setRegion(target) 842 .setRegion("") 843 .build() 844 .getCountry(); 845 assertEquals("empty", defaulted, result); 846 847 // setting with null also resets 848 result = builder 849 .setRegion(target) 850 .setRegion(null) 851 .build() 852 .getCountry(); 853 assertEquals("null", defaulted, result); 854 855 // ill-formed region codes throw IAE 856 // 2 alpha or 3 numeric 857 new BuilderILE("q", "abc", "12", "1234", "a3", "12a") { public void call() { b.setRegion(arg); }}; 858 859 // region code validation is NOT performed, any 2-alpha or 3-digit passes 860 assertEquals("2alpha", "ZZ", builder.setRegion("ZZ").build().getCountry()); 861 assertEquals("3digit", "000", builder.setRegion("000").build().getCountry()); 862 } 863 864 public void testBuilderSetVariant() { 865 // Variant case is not normalized in lenient variant mode 866 String source = "NewYork"; 867 String target = source; 868 String defaulted = ""; 869 Builder builder = new Builder(); 870 String result = builder 871 .setVariant(source) 872 .build() 873 .getVariant(); 874 assertEquals("NewYork", target, result); 875 876 result = builder 877 .setVariant("NeWeR_YoRkEr") 878 .build() 879 .toLanguageTag(); 880 assertEquals("newer yorker", "und-NeWeR-YoRkEr", result); 881 882 // subtags of variant are NOT reordered 883 result = builder 884 .setVariant("zzzzz_yyyyy_xxxxx") 885 .build() 886 .getVariant(); 887 assertEquals("zyx", "zzzzz_yyyyy_xxxxx", result); 888 889 // setting to empty resets 890 result = builder 891 .setVariant(target) 892 .setVariant("") 893 .build() 894 .getVariant(); 895 assertEquals("empty", defaulted, result); 896 897 // setting to null also resets 898 result = builder 899 .setVariant(target) 900 .setVariant(null) 901 .build() 902 .getVariant(); 903 assertEquals("null", defaulted, result); 904 905 // ill-formed variants throw IAE 906 // digit followed by 3-7 characters, or alpha followed by 4-8 characters. 907 new BuilderILE("abcd", "abcdefghi", "1ab", "1abcdefgh") { public void call() { b.setVariant(arg); }}; 908 909 // 4 characters is ok as long as the first is a digit 910 assertEquals("digit+3alpha", "1abc", builder.setVariant("1abc").build().getVariant()); 911 912 // all subfields must conform 913 new BuilderILE("abcde-fg") { public void call() { b.setVariant(arg); }}; 914 } 915 916 public void testBuilderSetExtension() { 917 // upper case characters are normalized to lower case 918 final char sourceKey = 'a'; 919 final String sourceValue = "aB-aBcdefgh-12-12345678"; 920 String target = "ab-abcdefgh-12-12345678"; 921 Builder builder = new Builder(); 922 String result = builder 923 .setExtension(sourceKey, sourceValue) 924 .build() 925 .getExtension(sourceKey); 926 assertEquals("extension", target, result); 927 928 // setting with empty resets 929 result = builder 930 .setExtension(sourceKey, sourceValue) 931 .setExtension(sourceKey, "") 932 .build() 933 .getExtension(sourceKey); 934 assertEquals("empty", null, result); 935 936 // setting with null also resets 937 result = builder 938 .setExtension(sourceKey, sourceValue) 939 .setExtension(sourceKey, null) 940 .build() 941 .getExtension(sourceKey); 942 assertEquals("null", null, result); 943 944 // ill-formed extension keys throw IAE 945 // must be in [0-9a-ZA-Z] 946 new BuilderILE("$") { public void call() { b.setExtension('$', sourceValue); }}; 947 948 // each segment of value must be 2-8 alphanum 949 new BuilderILE("ab-cd-123456789") { public void call() { b.setExtension(sourceKey, arg); }}; 950 951 // no multiple hyphens. 952 new BuilderILE("ab--cd") { public void call() { b.setExtension(sourceKey, arg); }}; 953 954 // locale extension key has special handling 955 Locale locale = builder 956 .setExtension('u', "co-japanese") 957 .build(); 958 assertEquals("locale extension", "japanese", locale.getUnicodeLocaleType("co")); 959 960 // locale extension has same behavior with set locale keyword 961 Locale locale2 = builder 962 .setUnicodeLocaleKeyword("co", "japanese") 963 .build(); 964 assertEquals("locales with extension", locale, locale2); 965 966 // setting locale extension overrides all previous calls to setLocaleKeyword 967 Locale locale3 = builder 968 .setExtension('u', "xxx-nu-thai") 969 .build(); 970 assertEquals("remove co", null, locale3.getUnicodeLocaleType("co")); 971 assertEquals("override thai", "thai", locale3.getUnicodeLocaleType("nu")); 972 assertEquals("override attribute", 1, locale3.getUnicodeLocaleAttributes().size()); 973 974 // setting locale keyword extends values already set by the locale extension 975 Locale locale4 = builder 976 .setUnicodeLocaleKeyword("co", "japanese") 977 .build(); 978 assertEquals("extend", "japanese", locale4.getUnicodeLocaleType("co")); 979 assertEquals("extend", "thai", locale4.getUnicodeLocaleType("nu")); 980 981 // locale extension subtags are reordered 982 result = builder 983 .clear() 984 .setExtension('u', "456-123-zz-123-yy-456-xx-789") 985 .build() 986 .toLanguageTag(); 987 assertEquals("reorder", "und-u-123-456-xx-789-yy-456-zz-123", result); 988 989 // multiple keyword types 990 result = builder 991 .clear() 992 .setExtension('u', "nu-thai-foobar") 993 .build() 994 .getUnicodeLocaleType("nu"); 995 assertEquals("multiple types", "thai-foobar", result); 996 997 // redundant locale extensions are ignored 998 result = builder 999 .clear() 1000 .setExtension('u', "nu-thai-NU-chinese-xx-1234") 1001 .build() 1002 .toLanguageTag(); 1003 assertEquals("duplicate keys", "und-u-nu-thai-xx-1234", result); 1004 } 1005 1006 public void testBuilderAddUnicodeLocaleAttribute() { 1007 Builder builder = new Builder(); 1008 Locale locale = builder 1009 .addUnicodeLocaleAttribute("def") 1010 .addUnicodeLocaleAttribute("abc") 1011 .build(); 1012 1013 Set<String> uattrs = locale.getUnicodeLocaleAttributes(); 1014 assertEquals("number of attributes", 2, uattrs.size()); 1015 assertTrue("attribute abc", uattrs.contains("abc")); 1016 assertTrue("attribute def", uattrs.contains("def")); 1017 1018 // remove attribute 1019 locale = builder.removeUnicodeLocaleAttribute("xxx") 1020 .build(); 1021 1022 assertEquals("remove bogus", 2, uattrs.size()); 1023 1024 // add duplicate 1025 locale = builder.addUnicodeLocaleAttribute("abc") 1026 .build(); 1027 assertEquals("add duplicate", 2, uattrs.size()); 1028 1029 // null attribute throws NPE 1030 new BuilderNPE("null attribute") { public void call() { b.addUnicodeLocaleAttribute(null); }}; 1031 1032 // illformed attribute throws IllformedLocaleException 1033 new BuilderILE("invalid attribute") { public void call() { b.addUnicodeLocaleAttribute("ca"); }}; 1034 } 1035 1036 public void testBuildersetUnicodeLocaleKeyword() { 1037 // Note: most behavior is tested in testBuilderSetExtension 1038 Builder builder = new Builder(); 1039 Locale locale = builder 1040 .setUnicodeLocaleKeyword("co", "japanese") 1041 .setUnicodeLocaleKeyword("nu", "thai") 1042 .build(); 1043 assertEquals("co", "japanese", locale.getUnicodeLocaleType("co")); 1044 assertEquals("nu", "thai", locale.getUnicodeLocaleType("nu")); 1045 assertEquals("keys", 2, locale.getUnicodeLocaleKeys().size()); 1046 1047 // can clear a keyword by setting to null, others remain 1048 String result = builder 1049 .setUnicodeLocaleKeyword("co", null) 1050 .build() 1051 .toLanguageTag(); 1052 assertEquals("empty co", "und-u-nu-thai", result); 1053 1054 // locale keyword extension goes when all keywords are gone 1055 result = builder 1056 .setUnicodeLocaleKeyword("nu", null) 1057 .build() 1058 .toLanguageTag(); 1059 assertEquals("empty nu", "und", result); 1060 1061 // locale keywords are ordered independent of order of addition 1062 result = builder 1063 .setUnicodeLocaleKeyword("zz", "012") 1064 .setUnicodeLocaleKeyword("aa", "345") 1065 .build() 1066 .toLanguageTag(); 1067 assertEquals("reordered", "und-u-aa-345-zz-012", result); 1068 1069 // null keyword throws NPE 1070 new BuilderNPE("keyword") { public void call() { b.setUnicodeLocaleKeyword(null, "thai"); }}; 1071 1072 // well-formed keywords are two alphanum 1073 new BuilderILE("a", "abc") { public void call() { b.setUnicodeLocaleKeyword(arg, "value"); }}; 1074 1075 // well-formed values are 3-8 alphanum 1076 new BuilderILE("ab", "abcdefghi") { public void call() { b.setUnicodeLocaleKeyword("ab", arg); }}; 1077 } 1078 1079 public void testBuilderPrivateUseExtension() { 1080 // normalizes hyphens to underscore, case to lower 1081 String source = "c-B-a"; 1082 String target = "c-b-a"; 1083 Builder builder = new Builder(); 1084 String result = builder 1085 .setExtension(Locale.PRIVATE_USE_EXTENSION, source) 1086 .build() 1087 .getExtension(Locale.PRIVATE_USE_EXTENSION); 1088 assertEquals("abc", target, result); 1089 1090 // multiple hyphens are ill-formed 1091 new BuilderILE("a--b") { public void call() { b.setExtension(Locale.PRIVATE_USE_EXTENSION, arg); }}; 1092 } 1093 1094 public void testBuilderClear() { 1095 String monster = "en-latn-US-NewYork-a-bb-cc-u-co-japanese-x-z-y-x-x"; 1096 Builder builder = new Builder(); 1097 Locale locale = Locale.forLanguageTag(monster); 1098 String result = builder 1099 .setLocale(locale) 1100 .clear() 1101 .build() 1102 .toLanguageTag(); 1103 assertEquals("clear", "und", result); 1104 } 1105 1106 public void testBuilderRemoveUnicodeAttribute() { 1107 // tested in testBuilderAddUnicodeAttribute 1108 } 1109 1110 public void testBuilderBuild() { 1111 // tested in other test methods 1112 } 1113 1114 public void testSerialize() { 1115 final Locale[] testLocales = { 1116 Locale.ROOT, 1117 new Locale("en"), 1118 new Locale("en", "US"), 1119 new Locale("en", "US", "Win"), 1120 new Locale("en", "US", "Win_XP"), 1121 new Locale("ja", "JP"), 1122 new Locale("ja", "JP", "JP"), 1123 new Locale("th", "TH"), 1124 new Locale("th", "TH", "TH"), 1125 new Locale("no", "NO"), 1126 new Locale("nb", "NO"), 1127 new Locale("nn", "NO"), 1128 new Locale("no", "NO", "NY"), 1129 new Locale("nn", "NO", "NY"), 1130 new Locale("he", "IL"), 1131 new Locale("he", "IL", "var"), 1132 new Locale("Language", "Country", "Variant"), 1133 new Locale("", "US"), 1134 new Locale("", "", "Java"), 1135 Locale.forLanguageTag("en-Latn-US"), 1136 Locale.forLanguageTag("zh-Hans"), 1137 Locale.forLanguageTag("zh-Hant-TW"), 1138 Locale.forLanguageTag("ja-JP-u-ca-japanese"), 1139 Locale.forLanguageTag("und-Hant"), 1140 Locale.forLanguageTag("und-a-123-456"), 1141 Locale.forLanguageTag("en-x-java"), 1142 Locale.forLanguageTag("th-TH-u-ca-buddist-nu-thai-x-lvariant-TH"), 1143 }; 1144 1145 for (Locale locale : testLocales) { 1146 try { 1147 // write 1148 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1149 ObjectOutputStream oos = new ObjectOutputStream(bos); 1150 oos.writeObject(locale); 1151 1152 // read 1153 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 1154 ObjectInputStream ois = new ObjectInputStream(bis); 1155 Object o = ois.readObject(); 1156 1157 assertEquals("roundtrip " + locale, locale, o); 1158 } catch (Exception e) { 1159 errln(locale + " encountered exception:" + e.getLocalizedMessage()); 1160 } 1161 } 1162 } 1163 1164 public void testDeserialize6() { 1165 final String TESTFILEPREFIX = "java6locale_"; 1166 1167 File dataDir = null; 1168 String dataDirName = System.getProperty("serialized.data.dir"); 1169 if (dataDirName == null) { 1170 URL resdirUrl = getClass().getClassLoader().getResource("serialized"); 1171 if (resdirUrl != null) { 1172 try { 1173 dataDir = new File(resdirUrl.toURI()); 1174 } catch (URISyntaxException urie) { 1175 } 1176 } 1177 } else { 1178 dataDir = new File(dataDirName); 1179 } 1180 1181 if (dataDir == null || !dataDir.isDirectory()) { 1182 errln("Could not locate the serialized test case data location"); 1183 return; 1184 } 1185 1186 File[] files = dataDir.listFiles(); 1187 for (File testfile : files) { 1188 if (testfile.isDirectory()) { 1189 continue; 1190 } 1191 String name = testfile.getName(); 1192 if (!name.startsWith(TESTFILEPREFIX)) { 1193 continue; 1194 } 1195 Locale locale; 1196 String locStr = name.substring(TESTFILEPREFIX.length()); 1197 if (locStr.equals("ROOT")) { 1198 locale = Locale.ROOT; 1199 } else { 1200 String[] fields = locStr.split("_", 3); 1201 String lang = fields[0]; 1202 String country = (fields.length >= 2) ? fields[1] : ""; 1203 String variant = (fields.length == 3) ? fields[2] : ""; 1204 locale = new Locale(lang, country, variant); 1205 } 1206 1207 // deserialize 1208 try (FileInputStream fis = new FileInputStream(testfile); 1209 ObjectInputStream ois = new ObjectInputStream(fis)) 1210 { 1211 Object o = ois.readObject(); 1212 assertEquals("Deserialize Java 6 Locale " + locale, o, locale); 1213 } catch (Exception e) { 1214 errln("Exception while reading " + testfile.getAbsolutePath() + " - " + e.getMessage()); 1215 } 1216 } 1217 } 1218 1219 public void testBug7002320() { 1220 // forLanguageTag() and Builder.setLanguageTag(String) 1221 // should add a location extension for following two cases. 1222 // 1223 // 1. language/country are "ja"/"JP" and the resolved variant (x-lvariant-*) 1224 // is exactly "JP" and no BCP 47 extensions are available, then add 1225 // a Unicode locale extension "ca-japanese". 1226 // 2. language/country are "th"/"TH" and the resolved variant is exactly 1227 // "TH" and no BCP 47 extensions are available, then add a Unicode locale 1228 // extension "nu-thai". 1229 // 1230 String[][] testdata = { 1231 {"ja-JP-x-lvariant-JP", "ja-JP-u-ca-japanese-x-lvariant-JP"}, // special case 1 1232 {"ja-JP-x-lvariant-JP-XXX"}, 1233 {"ja-JP-u-ca-japanese-x-lvariant-JP"}, 1234 {"ja-JP-u-ca-gregory-x-lvariant-JP"}, 1235 {"ja-JP-u-cu-jpy-x-lvariant-JP"}, 1236 {"ja-x-lvariant-JP"}, 1237 {"th-TH-x-lvariant-TH", "th-TH-u-nu-thai-x-lvariant-TH"}, // special case 2 1238 {"th-TH-u-nu-thai-x-lvariant-TH"}, 1239 {"en-US-x-lvariant-JP"}, 1240 }; 1241 1242 Builder bldr = new Builder(); 1243 1244 for (String[] data : testdata) { 1245 String in = data[0]; 1246 String expected = (data.length == 1) ? data[0] : data[1]; 1247 1248 // forLanguageTag 1249 Locale loc = Locale.forLanguageTag(in); 1250 String out = loc.toLanguageTag(); 1251 assertEquals("Language tag roundtrip by forLanguageTag with input: " + in, expected, out); 1252 1253 // setLanguageTag 1254 bldr.clear(); 1255 bldr.setLanguageTag(in); 1256 loc = bldr.build(); 1257 out = loc.toLanguageTag(); 1258 assertEquals("Language tag roundtrip by Builder.setLanguageTag with input: " + in, expected, out); 1259 } 1260 } 1261 1262 public void testBug7023613() { 1263 String[][] testdata = { 1264 {"en-Latn", "en__#Latn"}, 1265 {"en-u-ca-japanese", "en__#u-ca-japanese"}, 1266 }; 1267 1268 for (String[] data : testdata) { 1269 String in = data[0]; 1270 String expected = (data.length == 1) ? data[0] : data[1]; 1271 1272 Locale loc = Locale.forLanguageTag(in); 1273 String out = loc.toString(); 1274 assertEquals("Empty country field with non-empty script/extension with input: " + in, expected, out); 1275 } 1276 } 1277 1278 /// 1279 /// utility asserts 1280 /// 1281 1282 private void assertTrue(String msg, boolean v) { 1283 if (!v) { 1284 errln(msg + ": expected true"); 1285 } 1286 } 1287 1288 private void assertFalse(String msg, boolean v) { 1289 if (v) { 1290 errln(msg + ": expected false"); 1291 } 1292 } 1293 1294 private void assertEquals(String msg, Object e, Object v) { 1295 if (e == null ? v != null : !e.equals(v)) { 1296 if (e != null) { 1297 e = "'" + e + "'"; 1298 } 1299 if (v != null) { 1300 v = "'" + v + "'"; 1301 } 1302 errln(msg + ": expected " + e + " but got " + v); 1303 } 1304 } 1305 1306 private void assertNotEquals(String msg, Object e, Object v) { 1307 if (e == null ? v == null : e.equals(v)) { 1308 if (e != null) { 1309 e = "'" + e + "'"; 1310 } 1311 errln(msg + ": expected not equal " + e); 1312 } 1313 } 1314 1315 private void assertNull(String msg, Object o) { 1316 if (o != null) { 1317 errln(msg + ": expected null but got '" + o + "'"); 1318 } 1319 } 1320 1321 private void assertNotNull(String msg, Object o) { 1322 if (o == null) { 1323 errln(msg + ": expected non null"); 1324 } 1325 } 1326 1327 // not currently used, might get rid of exceptions from the API 1328 private abstract class ExceptionTest { 1329 private final Class<? extends Exception> exceptionClass; 1330 1331 ExceptionTest(Class<? extends Exception> exceptionClass) { 1332 this.exceptionClass = exceptionClass; 1333 } 1334 1335 public void run() { 1336 String failMsg = null; 1337 try { 1338 call(); 1339 failMsg = "expected " + exceptionClass.getName() + " but no exception thrown."; 1340 } 1341 catch (Exception e) { 1342 if (!exceptionClass.isAssignableFrom(e.getClass())) { 1343 failMsg = "expected " + exceptionClass.getName() + " but caught " + e; 1344 } 1345 } 1346 if (failMsg != null) { 1347 String msg = message(); 1348 msg = msg == null ? "" : msg + " "; 1349 errln(msg + failMsg); 1350 } 1351 } 1352 1353 public String message() { 1354 return null; 1355 } 1356 1357 public abstract void call(); 1358 } 1359 1360 private abstract class ExpectNPE extends ExceptionTest { 1361 ExpectNPE() { 1362 super(NullPointerException.class); 1363 run(); 1364 } 1365 } 1366 1367 private abstract class BuilderNPE extends ExceptionTest { 1368 protected final String msg; 1369 protected final Builder b = new Builder(); 1370 1371 BuilderNPE(String msg) { 1372 super(NullPointerException.class); 1373 1374 this.msg = msg; 1375 1376 run(); 1377 } 1378 1379 public String message() { 1380 return msg; 1381 } 1382 } 1383 1384 private abstract class ExpectIAE extends ExceptionTest { 1385 ExpectIAE() { 1386 super(IllegalArgumentException.class); 1387 run(); 1388 } 1389 } 1390 1391 private abstract class BuilderILE extends ExceptionTest { 1392 protected final String[] args; 1393 protected final Builder b = new Builder(); 1394 1395 protected String arg; // mutates during call 1396 1397 BuilderILE(String... args) { 1398 super(IllformedLocaleException.class); 1399 1400 this.args = args; 1401 1402 run(); 1403 } 1404 1405 public void run() { 1406 for (String arg : args) { 1407 this.arg = arg; 1408 super.run(); 1409 } 1410 } 1411 1412 public String message() { 1413 return "arg: '" + arg + "'"; 1414 } 1415 } 1416 }