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