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