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