LocaleEnhanceTest.java revision 3966:21fa255f0edf
1259698Sdim/* 2259698Sdim * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 3259698Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4259698Sdim * 5259698Sdim * This code is free software; you can redistribute it and/or modify it 6259698Sdim * under the terms of the GNU General Public License version 2 only, as 7259698Sdim * published by the Free Software Foundation. Oracle designates this 8259698Sdim * particular file as subject to the "Classpath" exception as provided 9259698Sdim * by Oracle in the LICENSE file that accompanied this code. 10259698Sdim * 11259698Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 12259698Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13259698Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14259698Sdim * version 2 for more details (a copy is included in the LICENSE file that 15259698Sdim * accompanied this code). 16259698Sdim * 17259698Sdim * You should have received a copy of the GNU General Public License version 18259698Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19259698Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20259698Sdim * 21259698Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22259698Sdim * or visit www.oracle.com if you need additional information or have any 23259698Sdim * questions. 24259698Sdim */ 25259698Sdim 26259698Sdimimport java.io.BufferedReader; 27259698Sdimimport java.io.ByteArrayInputStream; 28259698Sdimimport java.io.ByteArrayOutputStream; 29259698Sdimimport java.io.File; 30259698Sdimimport java.io.FileInputStream; 31259698Sdimimport java.io.InputStreamReader; 32259698Sdimimport java.io.ObjectInputStream; 33259698Sdimimport java.io.ObjectOutputStream; 34259698Sdimimport java.net.URISyntaxException; 35259698Sdimimport java.net.URL; 36259698Sdimimport java.text.DecimalFormatSymbols; 37259698Sdimimport java.util.ArrayList; 38259698Sdimimport java.util.Arrays; 39259698Sdimimport java.util.Calendar; 40259698Sdimimport java.util.IllformedLocaleException; 41259698Sdimimport java.util.List; 42259698Sdimimport java.util.Locale; 43259698Sdimimport java.util.Locale.Builder; 44259698Sdimimport java.util.Set; 45259698Sdim 46259698Sdim/** 47259698Sdim * @test 48259698Sdim * @bug 6875847 6992272 7002320 7015500 7023613 7032820 7033504 49259698Sdim * @summary test API changes to Locale 50259698Sdim * @compile LocaleEnhanceTest.java 51259698Sdim * @run main/othervm -esa LocaleEnhanceTest 52259698Sdim */ 53259698Sdimpublic class LocaleEnhanceTest extends LocaleTestFmwk { 54259698Sdim 55259698Sdim public static void main(String[] args) throws Exception { 56259698Sdim List<String> argList = new ArrayList<String>(); 57259698Sdim argList.addAll(Arrays.asList(args)); 58259698Sdim argList.add("-nothrow"); 59259698Sdim new LocaleEnhanceTest().run(argList.toArray(new String[argList.size()])); 60259698Sdim } 61259698Sdim 62259698Sdim public LocaleEnhanceTest() { 63259698Sdim } 64259698Sdim 65259698Sdim /// 66259698Sdim /// Generic sanity tests 67259698Sdim /// 68259698Sdim 69259698Sdim /** A canonical language code. */ 70259698Sdim private static final String l = "en"; 71259698Sdim 72259698Sdim /** A canonical script code.. */ 73259698Sdim private static final String s = "Latn"; 74259698Sdim 75259698Sdim /** A canonical region code. */ 76259698Sdim private static final String c = "US"; 77259698Sdim 78259698Sdim /** A canonical variant code. */ 79259698Sdim private static final String v = "NewYork"; 80259698Sdim 81259698Sdim /** 82259698Sdim * Ensure that Builder builds locales that have the expected 83259698Sdim * tag and java6 ID. Note the odd cases for the ID. 84259698Sdim */ 85259698Sdim public void testCreateLocaleCanonicalValid() { 86259698Sdim String[] valids = { 87259698Sdim "en-Latn-US-NewYork", "en_US_NewYork_#Latn", 88259698Sdim "en-Latn-US", "en_US_#Latn", 89259698Sdim "en-Latn-NewYork", "en__NewYork_#Latn", // double underscore 90259698Sdim "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 // note, no localization data yet other than US 620 // this should break when we have localization data for DE 621 Locale.setDefault(Locale.GERMANY); 622 assertEquals("latn DE", "Latin", latnLocale.getDisplayScript()); 623 assertEquals("hans DE", "Simplified Han", hansLocale.getDisplayScript()); 624 625 Locale.setDefault(oldLocale); 626 } 627 628 public void testGetDisplayScriptWithLocale() { 629 Locale latnLocale = Locale.forLanguageTag("und-latn"); 630 Locale hansLocale = Locale.forLanguageTag("und-hans"); 631 632 assertEquals("latn US", "Latin", latnLocale.getDisplayScript(Locale.US)); 633 assertEquals("hans US", "Simplified Han", hansLocale.getDisplayScript(Locale.US)); 634 635 // note, no localization data yet other than US 636 // this should break when we have localization data for DE 637 assertEquals("latn DE", "Latin", latnLocale.getDisplayScript(Locale.GERMANY)); 638 assertEquals("hans DE", "Simplified Han", hansLocale.getDisplayScript(Locale.GERMANY)); 639 } 640 641 public void testGetDisplayName() { 642 final Locale[] testLocales = { 643 Locale.ROOT, 644 new Locale("en"), 645 new Locale("en", "US"), 646 new Locale("", "US"), 647 new Locale("no", "NO", "NY"), 648 new Locale("", "", "NY"), 649 Locale.forLanguageTag("zh-Hans"), 650 Locale.forLanguageTag("zh-Hant"), 651 Locale.forLanguageTag("zh-Hans-CN"), 652 Locale.forLanguageTag("und-Hans"), 653 }; 654 655 final String[] displayNameEnglish = { 656 "", 657 "English", 658 "English (United States)", 659 "United States", 660 "Norwegian (Norway,Nynorsk)", 661 "Nynorsk", 662 "Chinese (Simplified Han)", 663 "Chinese (Traditional Han)", 664 "Chinese (Simplified Han,China)", 665 "Simplified Han", 666 }; 667 668 final String[] displayNameSimplifiedChinese = { 669 "", 670 "\u82f1\u6587", 671 "\u82f1\u6587 (\u7f8e\u56fd)", 672 "\u7f8e\u56fd", 673 "\u632a\u5a01\u6587 (\u632a\u5a01,Nynorsk)", 674 "Nynorsk", 675 "\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587)", 676 "\u4e2d\u6587 (\u7e41\u4f53\u4e2d\u6587)", 677 "\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587,\u4e2d\u56fd)", 678 "\u7b80\u4f53\u4e2d\u6587", 679 }; 680 681 for (int i = 0; i < testLocales.length; i++) { 682 Locale loc = testLocales[i]; 683 assertEquals("English display name for " + loc.toLanguageTag(), 684 displayNameEnglish[i], loc.getDisplayName(Locale.ENGLISH)); 685 assertEquals("Simplified Chinese display name for " + loc.toLanguageTag(), 686 displayNameSimplifiedChinese[i], loc.getDisplayName(Locale.CHINA)); 687 } 688 } 689 690 /// 691 /// Builder tests 692 /// 693 694 public void testBuilderSetLocale() { 695 Builder builder = new Builder(); 696 Builder lenientBuilder = new Builder(); 697 698 String languageTag = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z"; 699 String target = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z"; 700 701 Locale locale = Locale.forLanguageTag(languageTag); 702 Locale result = lenientBuilder 703 .setLocale(locale) 704 .build(); 705 assertEquals("long tag", target, result.toLanguageTag()); 706 assertEquals("long tag", locale, result); 707 708 // null is illegal 709 new BuilderNPE("locale") { 710 public void call() { b.setLocale(null); } 711 }; 712 713 // builder canonicalizes the three legacy locales: 714 // ja_JP_JP, th_TH_TH, no_NY_NO. 715 locale = builder.setLocale(new Locale("ja", "JP", "JP")).build(); 716 assertEquals("ja_JP_JP languagetag", "ja-JP-u-ca-japanese", locale.toLanguageTag()); 717 assertEquals("ja_JP_JP variant", "", locale.getVariant()); 718 719 locale = builder.setLocale(new Locale("th", "TH", "TH")).build(); 720 assertEquals("th_TH_TH languagetag", "th-TH-u-nu-thai", locale.toLanguageTag()); 721 assertEquals("th_TH_TH variant", "", locale.getVariant()); 722 723 locale = builder.setLocale(new Locale("no", "NO", "NY")).build(); 724 assertEquals("no_NO_NY languagetag", "nn-NO", locale.toLanguageTag()); 725 assertEquals("no_NO_NY language", "nn", locale.getLanguage()); 726 assertEquals("no_NO_NY variant", "", locale.getVariant()); 727 728 // non-canonical, non-legacy locales are invalid 729 new BuilderILE("123_4567_89") { 730 public void call() { 731 b.setLocale(new Locale("123", "4567", "89")); 732 } 733 }; 734 } 735 736 public void testBuilderSetLanguageTag() { 737 String source = "eN-LaTn-Us-NewYork-A-Xx-B-Yy-X-1-2-3"; 738 String target = "en-Latn-US-NewYork-a-xx-b-yy-x-1-2-3"; 739 Builder builder = new Builder(); 740 String result = builder 741 .setLanguageTag(source) 742 .build() 743 .toLanguageTag(); 744 assertEquals("language", target, result); 745 746 // redundant extensions cause a failure 747 new BuilderILE() { public void call() { b.setLanguageTag("und-a-xx-yy-b-ww-A-00-11-c-vv"); }}; 748 749 // redundant Unicode locale extension keys within an Unicode locale extension cause a failure 750 new BuilderILE() { public void call() { b.setLanguageTag("und-u-nu-thai-NU-chinese-xx-1234"); }}; 751 } 752 753 public void testBuilderSetLanguage() { 754 // language is normalized to lower case 755 String source = "eN"; 756 String target = "en"; 757 String defaulted = ""; 758 Builder builder = new Builder(); 759 String result = builder 760 .setLanguage(source) 761 .build() 762 .getLanguage(); 763 assertEquals("en", target, result); 764 765 // setting with empty resets 766 result = builder 767 .setLanguage(target) 768 .setLanguage("") 769 .build() 770 .getLanguage(); 771 assertEquals("empty", defaulted, result); 772 773 // setting with null resets too 774 result = builder 775 .setLanguage(target) 776 .setLanguage(null) 777 .build() 778 .getLanguage(); 779 assertEquals("null", defaulted, result); 780 781 // language codes must be 2-8 alpha 782 // for forwards compatibility, 4-alpha and 5-8 alpha (registered) 783 // languages are accepted syntax 784 new BuilderILE("q", "abcdefghi", "13") { public void call() { b.setLanguage(arg); }}; 785 786 // language code validation is NOT performed, any 2-8-alpha passes 787 assertNotNull("2alpha", builder.setLanguage("zz").build()); 788 assertNotNull("8alpha", builder.setLanguage("abcdefgh").build()); 789 790 // three-letter language codes are NOT canonicalized to two-letter 791 result = builder 792 .setLanguage("eng") 793 .build() 794 .getLanguage(); 795 assertEquals("eng", "eng", result); 796 } 797 798 public void testBuilderSetScript() { 799 // script is normalized to title case 800 String source = "lAtN"; 801 String target = "Latn"; 802 String defaulted = ""; 803 Builder builder = new Builder(); 804 String result = builder 805 .setScript(source) 806 .build() 807 .getScript(); 808 assertEquals("script", target, result); 809 810 // setting with empty resets 811 result = builder 812 .setScript(target) 813 .setScript("") 814 .build() 815 .getScript(); 816 assertEquals("empty", defaulted, result); 817 818 // settting with null also resets 819 result = builder 820 .setScript(target) 821 .setScript(null) 822 .build() 823 .getScript(); 824 assertEquals("null", defaulted, result); 825 826 // ill-formed script codes throw IAE 827 // must be 4alpha 828 new BuilderILE("abc", "abcde", "l3tn") { public void call() { b.setScript(arg); }}; 829 830 // script code validation is NOT performed, any 4-alpha passes 831 assertEquals("4alpha", "Wxyz", builder.setScript("wxyz").build().getScript()); 832 } 833 834 public void testBuilderSetRegion() { 835 // region is normalized to upper case 836 String source = "uS"; 837 String target = "US"; 838 String defaulted = ""; 839 Builder builder = new Builder(); 840 String result = builder 841 .setRegion(source) 842 .build() 843 .getCountry(); 844 assertEquals("us", target, result); 845 846 // setting with empty resets 847 result = builder 848 .setRegion(target) 849 .setRegion("") 850 .build() 851 .getCountry(); 852 assertEquals("empty", defaulted, result); 853 854 // setting with null also resets 855 result = builder 856 .setRegion(target) 857 .setRegion(null) 858 .build() 859 .getCountry(); 860 assertEquals("null", defaulted, result); 861 862 // ill-formed region codes throw IAE 863 // 2 alpha or 3 numeric 864 new BuilderILE("q", "abc", "12", "1234", "a3", "12a") { public void call() { b.setRegion(arg); }}; 865 866 // region code validation is NOT performed, any 2-alpha or 3-digit passes 867 assertEquals("2alpha", "ZZ", builder.setRegion("ZZ").build().getCountry()); 868 assertEquals("3digit", "000", builder.setRegion("000").build().getCountry()); 869 } 870 871 public void testBuilderSetVariant() { 872 // Variant case is not normalized in lenient variant mode 873 String source = "NewYork"; 874 String target = source; 875 String defaulted = ""; 876 Builder builder = new Builder(); 877 String result = builder 878 .setVariant(source) 879 .build() 880 .getVariant(); 881 assertEquals("NewYork", target, result); 882 883 result = builder 884 .setVariant("NeWeR_YoRkEr") 885 .build() 886 .toLanguageTag(); 887 assertEquals("newer yorker", "und-NeWeR-YoRkEr", result); 888 889 // subtags of variant are NOT reordered 890 result = builder 891 .setVariant("zzzzz_yyyyy_xxxxx") 892 .build() 893 .getVariant(); 894 assertEquals("zyx", "zzzzz_yyyyy_xxxxx", result); 895 896 // setting to empty resets 897 result = builder 898 .setVariant(target) 899 .setVariant("") 900 .build() 901 .getVariant(); 902 assertEquals("empty", defaulted, result); 903 904 // setting to null also resets 905 result = builder 906 .setVariant(target) 907 .setVariant(null) 908 .build() 909 .getVariant(); 910 assertEquals("null", defaulted, result); 911 912 // ill-formed variants throw IAE 913 // digit followed by 3-7 characters, or alpha followed by 4-8 characters. 914 new BuilderILE("abcd", "abcdefghi", "1ab", "1abcdefgh") { public void call() { b.setVariant(arg); }}; 915 916 // 4 characters is ok as long as the first is a digit 917 assertEquals("digit+3alpha", "1abc", builder.setVariant("1abc").build().getVariant()); 918 919 // all subfields must conform 920 new BuilderILE("abcde-fg") { public void call() { b.setVariant(arg); }}; 921 } 922 923 public void testBuilderSetExtension() { 924 // upper case characters are normalized to lower case 925 final char sourceKey = 'a'; 926 final String sourceValue = "aB-aBcdefgh-12-12345678"; 927 String target = "ab-abcdefgh-12-12345678"; 928 Builder builder = new Builder(); 929 String result = builder 930 .setExtension(sourceKey, sourceValue) 931 .build() 932 .getExtension(sourceKey); 933 assertEquals("extension", target, result); 934 935 // setting with empty resets 936 result = builder 937 .setExtension(sourceKey, sourceValue) 938 .setExtension(sourceKey, "") 939 .build() 940 .getExtension(sourceKey); 941 assertEquals("empty", null, result); 942 943 // setting with null also resets 944 result = builder 945 .setExtension(sourceKey, sourceValue) 946 .setExtension(sourceKey, null) 947 .build() 948 .getExtension(sourceKey); 949 assertEquals("null", null, result); 950 951 // ill-formed extension keys throw IAE 952 // must be in [0-9a-ZA-Z] 953 new BuilderILE("$") { public void call() { b.setExtension('$', sourceValue); }}; 954 955 // each segment of value must be 2-8 alphanum 956 new BuilderILE("ab-cd-123456789") { public void call() { b.setExtension(sourceKey, arg); }}; 957 958 // no multiple hyphens. 959 new BuilderILE("ab--cd") { public void call() { b.setExtension(sourceKey, arg); }}; 960 961 // locale extension key has special handling 962 Locale locale = builder 963 .setExtension('u', "co-japanese") 964 .build(); 965 assertEquals("locale extension", "japanese", locale.getUnicodeLocaleType("co")); 966 967 // locale extension has same behavior with set locale keyword 968 Locale locale2 = builder 969 .setUnicodeLocaleKeyword("co", "japanese") 970 .build(); 971 assertEquals("locales with extension", locale, locale2); 972 973 // setting locale extension overrides all previous calls to setLocaleKeyword 974 Locale locale3 = builder 975 .setExtension('u', "xxx-nu-thai") 976 .build(); 977 assertEquals("remove co", null, locale3.getUnicodeLocaleType("co")); 978 assertEquals("override thai", "thai", locale3.getUnicodeLocaleType("nu")); 979 assertEquals("override attribute", 1, locale3.getUnicodeLocaleAttributes().size()); 980 981 // setting locale keyword extends values already set by the locale extension 982 Locale locale4 = builder 983 .setUnicodeLocaleKeyword("co", "japanese") 984 .build(); 985 assertEquals("extend", "japanese", locale4.getUnicodeLocaleType("co")); 986 assertEquals("extend", "thai", locale4.getUnicodeLocaleType("nu")); 987 988 // locale extension subtags are reordered 989 result = builder 990 .clear() 991 .setExtension('u', "456-123-zz-123-yy-456-xx-789") 992 .build() 993 .toLanguageTag(); 994 assertEquals("reorder", "und-u-123-456-xx-789-yy-456-zz-123", result); 995 996 // multiple keyword types 997 result = builder 998 .clear() 999 .setExtension('u', "nu-thai-foobar") 1000 .build() 1001 .getUnicodeLocaleType("nu"); 1002 assertEquals("multiple types", "thai-foobar", result); 1003 1004 // redundant locale extensions are ignored 1005 result = builder 1006 .clear() 1007 .setExtension('u', "nu-thai-NU-chinese-xx-1234") 1008 .build() 1009 .toLanguageTag(); 1010 assertEquals("duplicate keys", "und-u-nu-thai-xx-1234", result); 1011 } 1012 1013 public void testBuilderAddUnicodeLocaleAttribute() { 1014 Builder builder = new Builder(); 1015 Locale locale = builder 1016 .addUnicodeLocaleAttribute("def") 1017 .addUnicodeLocaleAttribute("abc") 1018 .build(); 1019 1020 Set<String> uattrs = locale.getUnicodeLocaleAttributes(); 1021 assertEquals("number of attributes", 2, uattrs.size()); 1022 assertTrue("attribute abc", uattrs.contains("abc")); 1023 assertTrue("attribute def", uattrs.contains("def")); 1024 1025 // remove attribute 1026 locale = builder.removeUnicodeLocaleAttribute("xxx") 1027 .build(); 1028 1029 assertEquals("remove bogus", 2, uattrs.size()); 1030 1031 // add duplicate 1032 locale = builder.addUnicodeLocaleAttribute("abc") 1033 .build(); 1034 assertEquals("add duplicate", 2, uattrs.size()); 1035 1036 // null attribute throws NPE 1037 new BuilderNPE("null attribute") { public void call() { b.addUnicodeLocaleAttribute(null); }}; 1038 1039 // illformed attribute throws IllformedLocaleException 1040 new BuilderILE("invalid attribute") { public void call() { b.addUnicodeLocaleAttribute("ca"); }}; 1041 } 1042 1043 public void testBuildersetUnicodeLocaleKeyword() { 1044 // Note: most behavior is tested in testBuilderSetExtension 1045 Builder builder = new Builder(); 1046 Locale locale = builder 1047 .setUnicodeLocaleKeyword("co", "japanese") 1048 .setUnicodeLocaleKeyword("nu", "thai") 1049 .build(); 1050 assertEquals("co", "japanese", locale.getUnicodeLocaleType("co")); 1051 assertEquals("nu", "thai", locale.getUnicodeLocaleType("nu")); 1052 assertEquals("keys", 2, locale.getUnicodeLocaleKeys().size()); 1053 1054 // can clear a keyword by setting to null, others remain 1055 String result = builder 1056 .setUnicodeLocaleKeyword("co", null) 1057 .build() 1058 .toLanguageTag(); 1059 assertEquals("empty co", "und-u-nu-thai", result); 1060 1061 // locale keyword extension goes when all keywords are gone 1062 result = builder 1063 .setUnicodeLocaleKeyword("nu", null) 1064 .build() 1065 .toLanguageTag(); 1066 assertEquals("empty nu", "und", result); 1067 1068 // locale keywords are ordered independent of order of addition 1069 result = builder 1070 .setUnicodeLocaleKeyword("zz", "012") 1071 .setUnicodeLocaleKeyword("aa", "345") 1072 .build() 1073 .toLanguageTag(); 1074 assertEquals("reordered", "und-u-aa-345-zz-012", result); 1075 1076 // null keyword throws NPE 1077 new BuilderNPE("keyword") { public void call() { b.setUnicodeLocaleKeyword(null, "thai"); }}; 1078 1079 // well-formed keywords are two alphanum 1080 new BuilderILE("a", "abc") { public void call() { b.setUnicodeLocaleKeyword(arg, "value"); }}; 1081 1082 // well-formed values are 3-8 alphanum 1083 new BuilderILE("ab", "abcdefghi") { public void call() { b.setUnicodeLocaleKeyword("ab", arg); }}; 1084 } 1085 1086 public void testBuilderPrivateUseExtension() { 1087 // normalizes hyphens to underscore, case to lower 1088 String source = "c-B-a"; 1089 String target = "c-b-a"; 1090 Builder builder = new Builder(); 1091 String result = builder 1092 .setExtension(Locale.PRIVATE_USE_EXTENSION, source) 1093 .build() 1094 .getExtension(Locale.PRIVATE_USE_EXTENSION); 1095 assertEquals("abc", target, result); 1096 1097 // multiple hyphens are ill-formed 1098 new BuilderILE("a--b") { public void call() { b.setExtension(Locale.PRIVATE_USE_EXTENSION, arg); }}; 1099 } 1100 1101 public void testBuilderClear() { 1102 String monster = "en-latn-US-NewYork-a-bb-cc-u-co-japanese-x-z-y-x-x"; 1103 Builder builder = new Builder(); 1104 Locale locale = Locale.forLanguageTag(monster); 1105 String result = builder 1106 .setLocale(locale) 1107 .clear() 1108 .build() 1109 .toLanguageTag(); 1110 assertEquals("clear", "und", result); 1111 } 1112 1113 public void testBuilderRemoveUnicodeAttribute() { 1114 // tested in testBuilderAddUnicodeAttribute 1115 } 1116 1117 public void testBuilderBuild() { 1118 // tested in other test methods 1119 } 1120 1121 public void testSerialize() { 1122 final Locale[] testLocales = { 1123 Locale.ROOT, 1124 new Locale("en"), 1125 new Locale("en", "US"), 1126 new Locale("en", "US", "Win"), 1127 new Locale("en", "US", "Win_XP"), 1128 new Locale("ja", "JP"), 1129 new Locale("ja", "JP", "JP"), 1130 new Locale("th", "TH"), 1131 new Locale("th", "TH", "TH"), 1132 new Locale("no", "NO"), 1133 new Locale("nb", "NO"), 1134 new Locale("nn", "NO"), 1135 new Locale("no", "NO", "NY"), 1136 new Locale("nn", "NO", "NY"), 1137 new Locale("he", "IL"), 1138 new Locale("he", "IL", "var"), 1139 new Locale("Language", "Country", "Variant"), 1140 new Locale("", "US"), 1141 new Locale("", "", "Java"), 1142 Locale.forLanguageTag("en-Latn-US"), 1143 Locale.forLanguageTag("zh-Hans"), 1144 Locale.forLanguageTag("zh-Hant-TW"), 1145 Locale.forLanguageTag("ja-JP-u-ca-japanese"), 1146 Locale.forLanguageTag("und-Hant"), 1147 Locale.forLanguageTag("und-a-123-456"), 1148 Locale.forLanguageTag("en-x-java"), 1149 Locale.forLanguageTag("th-TH-u-ca-buddist-nu-thai-x-lvariant-TH"), 1150 }; 1151 1152 for (Locale locale : testLocales) { 1153 try { 1154 // write 1155 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1156 ObjectOutputStream oos = new ObjectOutputStream(bos); 1157 oos.writeObject(locale); 1158 1159 // read 1160 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 1161 ObjectInputStream ois = new ObjectInputStream(bis); 1162 Object o = ois.readObject(); 1163 1164 assertEquals("roundtrip " + locale, locale, o); 1165 } catch (Exception e) { 1166 errln(locale + " encountered exception:" + e.getLocalizedMessage()); 1167 } 1168 } 1169 } 1170 1171 public void testDeserialize6() { 1172 final String TESTFILEPREFIX = "java6locale_"; 1173 1174 File dataDir = null; 1175 String dataDirName = System.getProperty("serialized.data.dir"); 1176 if (dataDirName == null) { 1177 URL resdirUrl = getClass().getClassLoader().getResource("serialized"); 1178 if (resdirUrl != null) { 1179 try { 1180 dataDir = new File(resdirUrl.toURI()); 1181 } catch (URISyntaxException urie) { 1182 } 1183 } 1184 } else { 1185 dataDir = new File(dataDirName); 1186 } 1187 1188 if (dataDir == null || !dataDir.isDirectory()) { 1189 errln("Could not locate the serialized test case data location"); 1190 return; 1191 } 1192 1193 File[] files = dataDir.listFiles(); 1194 for (File testfile : files) { 1195 if (testfile.isDirectory()) { 1196 continue; 1197 } 1198 String name = testfile.getName(); 1199 if (!name.startsWith(TESTFILEPREFIX)) { 1200 continue; 1201 } 1202 Locale locale; 1203 String locStr = name.substring(TESTFILEPREFIX.length()); 1204 if (locStr.equals("ROOT")) { 1205 locale = Locale.ROOT; 1206 } else { 1207 String[] fields = locStr.split("_", 3); 1208 String lang = fields[0]; 1209 String country = (fields.length >= 2) ? fields[1] : ""; 1210 String variant = (fields.length == 3) ? fields[2] : ""; 1211 locale = new Locale(lang, country, variant); 1212 } 1213 1214 // deserialize 1215 try (FileInputStream fis = new FileInputStream(testfile); 1216 ObjectInputStream ois = new ObjectInputStream(fis)) 1217 { 1218 Object o = ois.readObject(); 1219 assertEquals("Deserialize Java 6 Locale " + locale, o, locale); 1220 } catch (Exception e) { 1221 errln("Exception while reading " + testfile.getAbsolutePath() + " - " + e.getMessage()); 1222 } 1223 } 1224 } 1225 1226 public void testBug7002320() { 1227 // forLanguageTag() and Builder.setLanguageTag(String) 1228 // should add a location extension for following two cases. 1229 // 1230 // 1. language/country are "ja"/"JP" and the resolved variant (x-lvariant-*) 1231 // is exactly "JP" and no BCP 47 extensions are available, then add 1232 // a Unicode locale extension "ca-japanese". 1233 // 2. language/country are "th"/"TH" and the resolved variant is exactly 1234 // "TH" and no BCP 47 extensions are available, then add a Unicode locale 1235 // extension "nu-thai". 1236 // 1237 String[][] testdata = { 1238 {"ja-JP-x-lvariant-JP", "ja-JP-u-ca-japanese-x-lvariant-JP"}, // special case 1 1239 {"ja-JP-x-lvariant-JP-XXX"}, 1240 {"ja-JP-u-ca-japanese-x-lvariant-JP"}, 1241 {"ja-JP-u-ca-gregory-x-lvariant-JP"}, 1242 {"ja-JP-u-cu-jpy-x-lvariant-JP"}, 1243 {"ja-x-lvariant-JP"}, 1244 {"th-TH-x-lvariant-TH", "th-TH-u-nu-thai-x-lvariant-TH"}, // special case 2 1245 {"th-TH-u-nu-thai-x-lvariant-TH"}, 1246 {"en-US-x-lvariant-JP"}, 1247 }; 1248 1249 Builder bldr = new Builder(); 1250 1251 for (String[] data : testdata) { 1252 String in = data[0]; 1253 String expected = (data.length == 1) ? data[0] : data[1]; 1254 1255 // forLanguageTag 1256 Locale loc = Locale.forLanguageTag(in); 1257 String out = loc.toLanguageTag(); 1258 assertEquals("Language tag roundtrip by forLanguageTag with input: " + in, expected, out); 1259 1260 // setLanguageTag 1261 bldr.clear(); 1262 bldr.setLanguageTag(in); 1263 loc = bldr.build(); 1264 out = loc.toLanguageTag(); 1265 assertEquals("Language tag roundtrip by Builder.setLanguageTag with input: " + in, expected, out); 1266 } 1267 } 1268 1269 public void testBug7023613() { 1270 String[][] testdata = { 1271 {"en-Latn", "en__#Latn"}, 1272 {"en-u-ca-japanese", "en__#u-ca-japanese"}, 1273 }; 1274 1275 for (String[] data : testdata) { 1276 String in = data[0]; 1277 String expected = (data.length == 1) ? data[0] : data[1]; 1278 1279 Locale loc = Locale.forLanguageTag(in); 1280 String out = loc.toString(); 1281 assertEquals("Empty country field with non-empty script/extension with input: " + in, expected, out); 1282 } 1283 } 1284 1285 /* 1286 * 7033504: (lc) incompatible behavior change for ja_JP_JP and th_TH_TH locales 1287 */ 1288 public void testBug7033504() { 1289 checkCalendar(new Locale("ja", "JP", "jp"), "java.util.GregorianCalendar"); 1290 checkCalendar(new Locale("ja", "jp", "jp"), "java.util.GregorianCalendar"); 1291 checkCalendar(new Locale("ja", "JP", "JP"), "java.util.JapaneseImperialCalendar"); 1292 checkCalendar(new Locale("ja", "jp", "JP"), "java.util.JapaneseImperialCalendar"); 1293 checkCalendar(Locale.forLanguageTag("en-u-ca-japanese"), 1294 "java.util.JapaneseImperialCalendar"); 1295 1296 checkDigit(new Locale("th", "TH", "th"), '0'); 1297 checkDigit(new Locale("th", "th", "th"), '0'); 1298 checkDigit(new Locale("th", "TH", "TH"), '\u0e50'); 1299 checkDigit(new Locale("th", "TH", "TH"), '\u0e50'); 1300 checkDigit(Locale.forLanguageTag("en-u-nu-thai"), '\u0e50'); 1301 } 1302 1303 private void checkCalendar(Locale loc, String expected) { 1304 Calendar cal = Calendar.getInstance(loc); 1305 assertEquals("Wrong calendar", expected, cal.getClass().getName()); 1306 } 1307 1308 private void checkDigit(Locale loc, Character expected) { 1309 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(loc); 1310 Character zero = dfs.getZeroDigit(); 1311 assertEquals("Wrong digit zero char", expected, zero); 1312 } 1313 1314 /// 1315 /// utility asserts 1316 /// 1317 1318 private void assertTrue(String msg, boolean v) { 1319 if (!v) { 1320 errln(msg + ": expected true"); 1321 } 1322 } 1323 1324 private void assertFalse(String msg, boolean v) { 1325 if (v) { 1326 errln(msg + ": expected false"); 1327 } 1328 } 1329 1330 private void assertEquals(String msg, Object e, Object v) { 1331 if (e == null ? v != null : !e.equals(v)) { 1332 if (e != null) { 1333 e = "'" + e + "'"; 1334 } 1335 if (v != null) { 1336 v = "'" + v + "'"; 1337 } 1338 errln(msg + ": expected " + e + " but got " + v); 1339 } 1340 } 1341 1342 private void assertNotEquals(String msg, Object e, Object v) { 1343 if (e == null ? v == null : e.equals(v)) { 1344 if (e != null) { 1345 e = "'" + e + "'"; 1346 } 1347 errln(msg + ": expected not equal " + e); 1348 } 1349 } 1350 1351 private void assertNull(String msg, Object o) { 1352 if (o != null) { 1353 errln(msg + ": expected null but got '" + o + "'"); 1354 } 1355 } 1356 1357 private void assertNotNull(String msg, Object o) { 1358 if (o == null) { 1359 errln(msg + ": expected non null"); 1360 } 1361 } 1362 1363 // not currently used, might get rid of exceptions from the API 1364 private abstract class ExceptionTest { 1365 private final Class<? extends Exception> exceptionClass; 1366 1367 ExceptionTest(Class<? extends Exception> exceptionClass) { 1368 this.exceptionClass = exceptionClass; 1369 } 1370 1371 public void run() { 1372 String failMsg = null; 1373 try { 1374 call(); 1375 failMsg = "expected " + exceptionClass.getName() + " but no exception thrown."; 1376 } 1377 catch (Exception e) { 1378 if (!exceptionClass.isAssignableFrom(e.getClass())) { 1379 failMsg = "expected " + exceptionClass.getName() + " but caught " + e; 1380 } 1381 } 1382 if (failMsg != null) { 1383 String msg = message(); 1384 msg = msg == null ? "" : msg + " "; 1385 errln(msg + failMsg); 1386 } 1387 } 1388 1389 public String message() { 1390 return null; 1391 } 1392 1393 public abstract void call(); 1394 } 1395 1396 private abstract class ExpectNPE extends ExceptionTest { 1397 ExpectNPE() { 1398 super(NullPointerException.class); 1399 run(); 1400 } 1401 } 1402 1403 private abstract class BuilderNPE extends ExceptionTest { 1404 protected final String msg; 1405 protected final Builder b = new Builder(); 1406 1407 BuilderNPE(String msg) { 1408 super(NullPointerException.class); 1409 1410 this.msg = msg; 1411 1412 run(); 1413 } 1414 1415 public String message() { 1416 return msg; 1417 } 1418 } 1419 1420 private abstract class ExpectIAE extends ExceptionTest { 1421 ExpectIAE() { 1422 super(IllegalArgumentException.class); 1423 run(); 1424 } 1425 } 1426 1427 private abstract class BuilderILE extends ExceptionTest { 1428 protected final String[] args; 1429 protected final Builder b = new Builder(); 1430 1431 protected String arg; // mutates during call 1432 1433 BuilderILE(String... args) { 1434 super(IllformedLocaleException.class); 1435 1436 this.args = args; 1437 1438 run(); 1439 } 1440 1441 public void run() { 1442 for (String arg : args) { 1443 this.arg = arg; 1444 super.run(); 1445 } 1446 } 1447 1448 public String message() { 1449 return "arg: '" + arg + "'"; 1450 } 1451 } 1452} 1453