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