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