Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/Locale/LocaleEnhanceTest.java
38813 views
/*1* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.BufferedReader;24import java.io.ByteArrayInputStream;25import java.io.ByteArrayOutputStream;26import java.io.File;27import java.io.FileInputStream;28import java.io.InputStreamReader;29import java.io.ObjectInputStream;30import java.io.ObjectOutputStream;31import java.net.URISyntaxException;32import java.net.URL;33import java.text.DecimalFormatSymbols;34import java.util.ArrayList;35import java.util.Arrays;36import java.util.Calendar;37import java.util.IllformedLocaleException;38import java.util.List;39import java.util.Locale;40import java.util.Locale.Builder;41import java.util.Set;4243/**44* @test45* @bug 6875847 6992272 7002320 7015500 7023613 7032820 7033504 700460346* 7044019 825508647* @summary test API changes to Locale48* @compile LocaleEnhanceTest.java49* @run main/othervm -esa LocaleEnhanceTest50*/51public class LocaleEnhanceTest extends LocaleTestFmwk {5253public static void main(String[] args) throws Exception {54List<String> argList = new ArrayList<String>();55argList.addAll(Arrays.asList(args));56argList.add("-nothrow");57new LocaleEnhanceTest().run(argList.toArray(new String[argList.size()]));58}5960public LocaleEnhanceTest() {61}6263///64/// Generic sanity tests65///6667/** A canonical language code. */68private static final String l = "en";6970/** A canonical script code.. */71private static final String s = "Latn";7273/** A canonical region code. */74private static final String c = "US";7576/** A canonical variant code. */77private static final String v = "NewYork";7879/**80* Ensure that Builder builds locales that have the expected81* tag and java6 ID. Note the odd cases for the ID.82*/83public void testCreateLocaleCanonicalValid() {84String[] valids = {85"en-Latn-US-NewYork", "en_US_NewYork_#Latn",86"en-Latn-US", "en_US_#Latn",87"en-Latn-NewYork", "en__NewYork_#Latn", // double underscore88"en-Latn", "en__#Latn", // double underscore89"en-US-NewYork", "en_US_NewYork",90"en-US", "en_US",91"en-NewYork", "en__NewYork", // double underscore92"en", "en",93"und-Latn-US-NewYork", "_US_NewYork_#Latn",94"und-Latn-US", "_US_#Latn",95"und-Latn-NewYork", "", // variant only not supported96"und-Latn", "",97"und-US-NewYork", "_US_NewYork",98"und-US", "_US",99"und-NewYork", "", // variant only not supported100"und", ""101};102103Builder builder = new Builder();104105for (int i = 0; i < valids.length; i += 2) {106String tag = valids[i];107String id = valids[i+1];108109String idl = (i & 16) == 0 ? l : "";110String ids = (i & 8) == 0 ? s : "";111String idc = (i & 4) == 0 ? c : "";112String idv = (i & 2) == 0 ? v : "";113114String msg = String.valueOf(i/2) + ": '" + tag + "' ";115116try {117Locale l = builder118.setLanguage(idl)119.setScript(ids)120.setRegion(idc)121.setVariant(idv)122.build();123assertEquals(msg + "language", idl, l.getLanguage());124assertEquals(msg + "script", ids, l.getScript());125assertEquals(msg + "country", idc, l.getCountry());126assertEquals(msg + "variant", idv, l.getVariant());127assertEquals(msg + "tag", tag, l.toLanguageTag());128assertEquals(msg + "id", id, l.toString());129}130catch (IllegalArgumentException e) {131errln(msg + e.getMessage());132}133}134}135136/**137* Test that locale construction works with 'multiple variants'.138* <p>139* The string "Newer__Yorker" is treated as three subtags,140* "Newer", "", and "Yorker", and concatenated into one141* subtag by omitting empty subtags and joining the remainer142* with underscores. So the resulting variant tag is "Newer_Yorker".143* Note that 'New' and 'York' are invalid BCP47 variant subtags144* because they are too short.145*/146public void testCreateLocaleMultipleVariants() {147148String[] valids = {149"en-Latn-US-Newer-Yorker", "en_US_Newer_Yorker_#Latn",150"en-Latn-Newer-Yorker", "en__Newer_Yorker_#Latn",151"en-US-Newer-Yorker", "en_US_Newer_Yorker",152"en-Newer-Yorker", "en__Newer_Yorker",153"und-Latn-US-Newer-Yorker", "_US_Newer_Yorker_#Latn",154"und-Latn-Newer-Yorker", "",155"und-US-Newer-Yorker", "_US_Newer_Yorker",156"und-Newer-Yorker", "",157};158159Builder builder = new Builder(); // lenient variant160161final String idv = "Newer_Yorker";162for (int i = 0; i < valids.length; i += 2) {163String tag = valids[i];164String id = valids[i+1];165166String idl = (i & 8) == 0 ? l : "";167String ids = (i & 4) == 0 ? s : "";168String idc = (i & 2) == 0 ? c : "";169170String msg = String.valueOf(i/2) + ": " + tag + " ";171try {172Locale l = builder173.setLanguage(idl)174.setScript(ids)175.setRegion(idc)176.setVariant(idv)177.build();178179assertEquals(msg + " language", idl, l.getLanguage());180assertEquals(msg + " script", ids, l.getScript());181assertEquals(msg + " country", idc, l.getCountry());182assertEquals(msg + " variant", idv, l.getVariant());183184assertEquals(msg + "tag", tag, l.toLanguageTag());185assertEquals(msg + "id", id, l.toString());186}187catch (IllegalArgumentException e) {188errln(msg + e.getMessage());189}190}191}192193/**194* Ensure that all these invalid formats are not recognized by195* forLanguageTag.196*/197public void testCreateLocaleCanonicalInvalidSeparator() {198String[] invalids = {199// trailing separator200"en_Latn_US_NewYork_",201"en_Latn_US_",202"en_Latn_",203"en_",204"_",205206// double separator207"en_Latn_US__NewYork",208"_Latn_US__NewYork",209"en_US__NewYork",210"_US__NewYork",211212// are these OK?213// "en_Latn__US_NewYork", // variant is 'US_NewYork'214// "_Latn__US_NewYork", // variant is 'US_NewYork'215// "en__Latn_US_NewYork", // variant is 'Latn_US_NewYork'216// "en__US_NewYork", // variant is 'US_NewYork'217218// double separator without language or script219"__US",220"__NewYork",221222// triple separator anywhere except within variant223"en___NewYork",224"en_Latn___NewYork",225"_Latn___NewYork",226"___NewYork",227};228229for (int i = 0; i < invalids.length; ++i) {230String id = invalids[i];231Locale l = Locale.forLanguageTag(id);232assertEquals(id, "und", l.toLanguageTag());233}234}235236/**237* Ensure that all current locale ids parse. Use DateFormat as a proxy238* for all current locale ids.239*/240public void testCurrentLocales() {241Locale[] locales = java.text.DateFormat.getAvailableLocales();242Builder builder = new Builder();243244for (Locale target : locales) {245String tag = target.toLanguageTag();246247// the tag recreates the original locale,248// except no_NO_NY249Locale tagResult = Locale.forLanguageTag(tag);250if (!target.getVariant().equals("NY")) {251assertEquals("tagResult", target, tagResult);252}253254// the builder also recreates the original locale,255// except ja_JP_JP, th_TH_TH and no_NO_NY256Locale builderResult = builder.setLocale(target).build();257if (target.getVariant().length() != 2) {258assertEquals("builderResult", target, builderResult);259}260}261}262263/**264* Ensure that all icu locale ids parse.265*/266public void testIcuLocales() throws Exception {267BufferedReader br = new BufferedReader(268new InputStreamReader(269LocaleEnhanceTest.class.getResourceAsStream("icuLocales.txt"),270"UTF-8"));271String id = null;272while (null != (id = br.readLine())) {273Locale result = Locale.forLanguageTag(id);274assertEquals("ulocale", id, result.toLanguageTag());275}276}277278///279/// Compatibility tests280///281282public void testConstructor() {283// all the old weirdness still holds, no new weirdness284String[][] tests = {285// language to lower case, region to upper, variant unchanged286// short287{ "X", "y", "z", "x", "Y" },288// long289{ "xXxXxXxXxXxX", "yYyYyYyYyYyYyYyY", "zZzZzZzZzZzZzZzZ",290"xxxxxxxxxxxx", "YYYYYYYYYYYYYYYY" },291// mapped language ids292{ "he", "IW", "", "iw" },293{ "iw", "IW", "", "iw" },294{ "yi", "DE", "", "ji" },295{ "ji", "DE", "", "ji" },296{ "id", "ID", "", "in" },297{ "in", "ID", "", "in" },298// special variants299{ "ja", "JP", "JP" },300{ "th", "TH", "TH" },301{ "no", "NO", "NY" },302{ "no", "NO", "NY" },303// no canonicalization of 3-letter language codes304{ "eng", "US", "" }305};306for (int i = 0; i < tests.length; ++ i) {307String[] test = tests[i];308String id = String.valueOf(i);309Locale locale = new Locale(test[0], test[1], test[2]);310assertEquals(id + " lang", test.length > 3 ? test[3] : test[0], locale.getLanguage());311assertEquals(id + " region", test.length > 4 ? test[4] : test[1], locale.getCountry());312assertEquals(id + " variant", test.length > 5 ? test[5] : test[2], locale.getVariant());313}314}315316///317/// Locale API tests.318///319320public void testGetScript() {321// forLanguageTag normalizes case322Locale locale = Locale.forLanguageTag("und-latn");323assertEquals("forLanguageTag", "Latn", locale.getScript());324325// Builder normalizes case326locale = new Builder().setScript("LATN").build();327assertEquals("builder", "Latn", locale.getScript());328329// empty string is returned, not null, if there is no script330locale = Locale.forLanguageTag("und");331assertEquals("script is empty string", "", locale.getScript());332}333334public void testGetExtension() {335// forLanguageTag does NOT normalize to hyphen336Locale locale = Locale.forLanguageTag("und-a-some_ex-tension");337assertEquals("some_ex-tension", null, locale.getExtension('a'));338339// regular extension340locale = new Builder().setExtension('a', "some-ex-tension").build();341assertEquals("builder", "some-ex-tension", locale.getExtension('a'));342343// returns null if extension is not present344assertEquals("empty b", null, locale.getExtension('b'));345346// throws exception if extension tag is illegal347new ExpectIAE() { public void call() { Locale.forLanguageTag("").getExtension('\uD800'); }};348349// 'x' is not an extension, it's a private use tag, but it's accessed through this API350locale = Locale.forLanguageTag("x-y-z-blork");351assertEquals("x", "y-z-blork", locale.getExtension('x'));352}353354public void testGetExtensionKeys() {355Locale locale = Locale.forLanguageTag("und-a-xx-yy-b-zz-ww");356Set<Character> result = locale.getExtensionKeys();357assertEquals("result size", 2, result.size());358assertTrue("'a','b'", result.contains('a') && result.contains('b'));359360// result is not mutable361try {362result.add('x');363errln("expected exception on add to extension key set");364}365catch (UnsupportedOperationException e) {366// ok367}368369// returns empty set if no extensions370locale = Locale.forLanguageTag("und");371assertTrue("empty result", locale.getExtensionKeys().isEmpty());372}373374public void testGetUnicodeLocaleAttributes() {375Locale locale = Locale.forLanguageTag("en-US-u-abc-def");376Set<String> attributes = locale.getUnicodeLocaleAttributes();377assertEquals("number of attributes", 2, attributes.size());378assertTrue("attribute abc", attributes.contains("abc"));379assertTrue("attribute def", attributes.contains("def"));380381locale = Locale.forLanguageTag("en-US-u-ca-gregory");382attributes = locale.getUnicodeLocaleAttributes();383assertTrue("empty attributes", attributes.isEmpty());384}385386public void testGetUnicodeLocaleType() {387Locale locale = Locale.forLanguageTag("und-u-co-japanese-nu-thai");388assertEquals("collation", "japanese", locale.getUnicodeLocaleType("co"));389assertEquals("numbers", "thai", locale.getUnicodeLocaleType("nu"));390391// Unicode locale extension key is case insensitive392assertEquals("key case", "japanese", locale.getUnicodeLocaleType("Co"));393394// if keyword is not present, returns null395assertEquals("locale keyword not present", null, locale.getUnicodeLocaleType("xx"));396397// if no locale extension is set, returns null398locale = Locale.forLanguageTag("und");399assertEquals("locale extension not present", null, locale.getUnicodeLocaleType("co"));400401// typeless keyword402locale = Locale.forLanguageTag("und-u-kn");403assertEquals("typeless keyword", "", locale.getUnicodeLocaleType("kn"));404405// invalid keys throw exception406new ExpectIAE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType("q"); }};407new ExpectIAE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType("abcdefghi"); }};408409// null argument throws exception410new ExpectNPE() { public void call() { Locale.forLanguageTag("").getUnicodeLocaleType(null); }};411}412413public void testGetUnicodeLocaleKeys() {414Locale locale = Locale.forLanguageTag("und-u-co-japanese-nu-thai");415Set<String> result = locale.getUnicodeLocaleKeys();416assertEquals("two keys", 2, result.size());417assertTrue("co and nu", result.contains("co") && result.contains("nu"));418419// result is not modifiable420try {421result.add("frobozz");422errln("expected exception when add to locale key set");423}424catch (UnsupportedOperationException e) {425// ok426}427}428429public void testPrivateUseExtension() {430Locale locale = Locale.forLanguageTag("x-y-x-blork-");431assertEquals("blork", "y-x-blork", locale.getExtension(Locale.PRIVATE_USE_EXTENSION));432433locale = Locale.forLanguageTag("und");434assertEquals("no privateuse", null, locale.getExtension(Locale.PRIVATE_USE_EXTENSION));435}436437public void testToLanguageTag() {438// lots of normalization to test here439// test locales created using the constructor440String[][] tests = {441// empty locale canonicalizes to 'und'442{ "", "", "", "und" },443// variant alone is not a valid Locale, but has a valid language tag444{ "", "", "NewYork", "und-NewYork" },445// standard valid locales446{ "", "Us", "", "und-US" },447{ "", "US", "NewYork", "und-US-NewYork" },448{ "EN", "", "", "en" },449{ "EN", "", "NewYork", "en-NewYork" },450{ "EN", "US", "", "en-US" },451{ "EN", "US", "NewYork", "en-US-NewYork" },452// underscore in variant will be emitted as multiple variant subtags453{ "en", "US", "Newer_Yorker", "en-US-Newer-Yorker" },454// invalid variant subtags are appended as private use455{ "en", "US", "new_yorker", "en-US-x-lvariant-new-yorker" },456// the first invalid variant subtags and following variant subtags are appended as private use457{ "en", "US", "Windows_XP_Home", "en-US-Windows-x-lvariant-XP-Home" },458// too long variant and following variant subtags disappear459{ "en", "US", "WindowsVista_SP2", "en-US" },460// invalid region subtag disappears461{ "en", "USA", "", "en" },462// invalid language tag disappears463{ "e", "US", "", "und-US" },464// three-letter language tags are not canonicalized465{ "Eng", "", "", "eng" },466// legacy languages canonicalize to modern equivalents467{ "he", "IW", "", "he-IW" },468{ "iw", "IW", "", "he-IW" },469{ "yi", "DE", "", "yi-DE" },470{ "ji", "DE", "", "yi-DE" },471{ "id", "ID", "", "id-ID" },472{ "in", "ID", "", "id-ID" },473// special values are converted on output474{ "ja", "JP", "JP", "ja-JP-u-ca-japanese-x-lvariant-JP" },475{ "th", "TH", "TH", "th-TH-u-nu-thai-x-lvariant-TH" },476{ "no", "NO", "NY", "nn-NO" }477};478for (int i = 0; i < tests.length; ++i) {479String[] test = tests[i];480Locale locale = new Locale(test[0], test[1], test[2]);481assertEquals("case " + i, test[3], locale.toLanguageTag());482}483484// test locales created from forLanguageTag485String[][] tests1 = {486// case is normalized during the round trip487{ "EN-us", "en-US" },488{ "en-Latn-US", "en-Latn-US" },489// reordering Unicode locale extensions490{ "de-u-co-phonebk-ca-gregory", "de-u-ca-gregory-co-phonebk" },491// private use only language tag is preserved (no extra "und")492{ "x-elmer", "x-elmer" },493{ "x-lvariant-JP", "x-lvariant-JP" },494};495for (String[] test : tests1) {496Locale locale = Locale.forLanguageTag(test[0]);497assertEquals("case " + test[0], test[1], locale.toLanguageTag());498}499500}501502public void testForLanguageTag() {503// forLanguageTag implements the 'Language-Tag' production of504// BCP47, so it handles private use and grandfathered tags,505// unlike locale builder. Tags listed below (except for the506// sample private use tags) come from 4646bis Feb 29, 2009.507508String[][] tests = {509// private use tags only510{ "x-abc", "x-abc" },511{ "x-a-b-c", "x-a-b-c" },512{ "x-a-12345678", "x-a-12345678" },513514// grandfathered tags with preferred mappings515{ "i-ami", "ami" },516{ "i-bnn", "bnn" },517{ "i-hak", "hak" },518{ "i-klingon", "tlh" },519{ "i-lux", "lb" }, // two-letter tag520{ "i-navajo", "nv" }, // two-letter tag521{ "i-pwn", "pwn" },522{ "i-tao", "tao" },523{ "i-tay", "tay" },524{ "i-tsu", "tsu" },525{ "art-lojban", "jbo" },526{ "no-bok", "nb" },527{ "no-nyn", "nn" },528{ "sgn-BE-FR", "sfb" },529{ "sgn-BE-NL", "vgt" },530{ "sgn-CH-DE", "sgg" },531{ "zh-guoyu", "cmn" },532{ "zh-hakka", "hak" },533{ "zh-min-nan", "nan" },534{ "zh-xiang", "hsn" },535536// grandfathered irregular tags, no preferred mappings, drop illegal fields537// from end. If no subtag is mappable, fallback to 'und'538{ "i-default", "en-x-i-default" },539{ "i-enochian", "x-i-enochian" },540{ "i-mingo", "see-x-i-mingo" },541{ "en-GB-oed", "en-GB-x-oed" },542{ "zh-min", "nan-x-zh-min" },543{ "cel-gaulish", "xtg-x-cel-gaulish" },544};545for (int i = 0; i < tests.length; ++i) {546String[] test = tests[i];547Locale locale = Locale.forLanguageTag(test[0]);548assertEquals("grandfathered case " + i, test[1], locale.toLanguageTag());549}550551// forLanguageTag ignores everything past the first place it encounters552// a syntax error553tests = new String[][] {554{ "valid",555"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-12345678-z",556"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-12345678-z" },557{ "segment of private use tag too long",558"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y-123456789-z",559"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y" },560{ "segment of private use tag is empty",561"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y--12345678-z",562"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x-y" },563{ "first segment of private use tag is empty",564"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-x--y-12345678-z",565"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def" },566{ "illegal extension tag",567"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def-\uD800-y-12345678-z",568"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-def" },569{ "locale subtag with no value",570"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-x-y-12345678-z",571"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-bb-x-y-12345678-z" },572{ "locale key subtag invalid",573"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc-123456789-def-x-y-12345678-z",574"en-US-Newer-Yorker-a-bb-cc-dd-u-aa-abc" },575// locale key subtag invalid in earlier position, all following subtags576// dropped (and so the locale extension dropped as well)577{ "locale key subtag invalid in earlier position",578"en-US-Newer-Yorker-a-bb-cc-dd-u-123456789-abc-bb-def-x-y-12345678-z",579"en-US-Newer-Yorker-a-bb-cc-dd" },580};581for (int i = 0; i < tests.length; ++i) {582String[] test = tests[i];583String msg = "syntax error case " + i + " " + test[0];584try {585Locale locale = Locale.forLanguageTag(test[1]);586assertEquals(msg, test[2], locale.toLanguageTag());587}588catch (IllegalArgumentException e) {589errln(msg + " caught exception: " + e);590}591}592593// duplicated extension are just ignored594Locale locale = Locale.forLanguageTag("und-d-aa-00-bb-01-D-AA-10-cc-11-c-1234");595assertEquals("extension", "aa-00-bb-01", locale.getExtension('d'));596assertEquals("extension c", "1234", locale.getExtension('c'));597598locale = Locale.forLanguageTag("und-U-ca-gregory-u-ca-japanese");599assertEquals("Unicode extension", "ca-gregory", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION));600601// redundant Unicode locale keys in an extension are ignored602locale = Locale.forLanguageTag("und-u-aa-000-bb-001-bB-002-cc-003-c-1234");603assertEquals("Unicode keywords", "aa-000-bb-001-cc-003", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION));604assertEquals("Duplicated Unicode locake key followed by an extension", "1234", locale.getExtension('c'));605}606607public void testGetDisplayScript() {608Locale latnLocale = Locale.forLanguageTag("und-latn");609Locale hansLocale = Locale.forLanguageTag("und-hans");610611Locale oldLocale = Locale.getDefault();612613Locale.setDefault(Locale.US);614assertEquals("latn US", "Latin", latnLocale.getDisplayScript());615assertEquals("hans US", "Simplified", hansLocale.getDisplayScript());616617Locale.setDefault(Locale.GERMANY);618assertEquals("latn DE", "Lateinisch", latnLocale.getDisplayScript());619assertEquals("hans DE", "Vereinfachte Chinesische Schrift", hansLocale.getDisplayScript());620621Locale.setDefault(oldLocale);622}623624public void testGetDisplayScriptWithLocale() {625Locale latnLocale = Locale.forLanguageTag("und-latn");626Locale hansLocale = Locale.forLanguageTag("und-hans");627628assertEquals("latn US", "Latin", latnLocale.getDisplayScript(Locale.US));629assertEquals("hans US", "Simplified", hansLocale.getDisplayScript(Locale.US));630631assertEquals("latn DE", "Lateinisch", latnLocale.getDisplayScript(Locale.GERMANY));632assertEquals("hans DE", "Vereinfachte Chinesische Schrift", hansLocale.getDisplayScript(Locale.GERMANY));633}634635public void testGetDisplayName() {636final Locale[] testLocales = {637Locale.ROOT,638new Locale("en"),639new Locale("en", "US"),640new Locale("", "US"),641new Locale("no", "NO", "NY"),642new Locale("", "", "NY"),643Locale.forLanguageTag("zh-Hans"),644Locale.forLanguageTag("zh-Hant"),645Locale.forLanguageTag("zh-Hans-CN"),646Locale.forLanguageTag("und-Hans"),647};648649final String[] displayNameEnglish = {650"",651"English",652"English (United States)",653"United States",654"Norwegian (Norway,Nynorsk)",655"Nynorsk",656"Chinese (Simplified)",657"Chinese (Traditional)",658"Chinese (Simplified,China)",659"Simplified",660};661662final String[] displayNameSimplifiedChinese = {663"",664"\u82f1\u6587",665"\u82f1\u6587 (\u7f8e\u56fd)",666"\u7f8e\u56fd",667"\u632a\u5a01\u6587 (\u632a\u5a01,Nynorsk)",668"Nynorsk",669"\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587)",670"\u4e2d\u6587 (\u7e41\u4f53\u4e2d\u6587)",671"\u4e2d\u6587 (\u7b80\u4f53\u4e2d\u6587,\u4e2d\u56fd)",672"\u7b80\u4f53\u4e2d\u6587",673};674675for (int i = 0; i < testLocales.length; i++) {676Locale loc = testLocales[i];677assertEquals("English display name for " + loc.toLanguageTag(),678displayNameEnglish[i], loc.getDisplayName(Locale.ENGLISH));679assertEquals("Simplified Chinese display name for " + loc.toLanguageTag(),680displayNameSimplifiedChinese[i], loc.getDisplayName(Locale.CHINA));681}682}683684///685/// Builder tests686///687688public void testBuilderSetLocale() {689Builder builder = new Builder();690Builder lenientBuilder = new Builder();691692String languageTag = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z";693String target = "en-Latn-US-NewYork-a-bb-ccc-u-co-japanese-x-y-z";694695Locale locale = Locale.forLanguageTag(languageTag);696Locale result = lenientBuilder697.setLocale(locale)698.build();699assertEquals("long tag", target, result.toLanguageTag());700assertEquals("long tag", locale, result);701702// null is illegal703new BuilderNPE("locale") {704public void call() { b.setLocale(null); }705};706707// builder canonicalizes the three legacy locales:708// ja_JP_JP, th_TH_TH, no_NY_NO.709locale = builder.setLocale(new Locale("ja", "JP", "JP")).build();710assertEquals("ja_JP_JP languagetag", "ja-JP-u-ca-japanese", locale.toLanguageTag());711assertEquals("ja_JP_JP variant", "", locale.getVariant());712713locale = builder.setLocale(new Locale("th", "TH", "TH")).build();714assertEquals("th_TH_TH languagetag", "th-TH-u-nu-thai", locale.toLanguageTag());715assertEquals("th_TH_TH variant", "", locale.getVariant());716717locale = builder.setLocale(new Locale("no", "NO", "NY")).build();718assertEquals("no_NO_NY languagetag", "nn-NO", locale.toLanguageTag());719assertEquals("no_NO_NY language", "nn", locale.getLanguage());720assertEquals("no_NO_NY variant", "", locale.getVariant());721722// non-canonical, non-legacy locales are invalid723new BuilderILE("123_4567_89") {724public void call() {725b.setLocale(new Locale("123", "4567", "89"));726}727};728}729730public void testBuilderSetLanguageTag() {731String source = "eN-LaTn-Us-NewYork-A-Xx-B-Yy-X-1-2-3";732String target = "en-Latn-US-NewYork-a-xx-b-yy-x-1-2-3";733Builder builder = new Builder();734String result = builder735.setLanguageTag(source)736.build()737.toLanguageTag();738assertEquals("language", target, result);739740// redundant extensions cause a failure741new BuilderILE() { public void call() { b.setLanguageTag("und-a-xx-yy-b-ww-A-00-11-c-vv"); }};742743// redundant Unicode locale extension keys within an Unicode locale extension cause a failure744new BuilderILE() { public void call() { b.setLanguageTag("und-u-nu-thai-NU-chinese-xx-1234"); }};745}746747public void testBuilderSetLanguage() {748// language is normalized to lower case749String source = "eN";750String target = "en";751String defaulted = "";752Builder builder = new Builder();753String result = builder754.setLanguage(source)755.build()756.getLanguage();757assertEquals("en", target, result);758759// setting with empty resets760result = builder761.setLanguage(target)762.setLanguage("")763.build()764.getLanguage();765assertEquals("empty", defaulted, result);766767// setting with null resets too768result = builder769.setLanguage(target)770.setLanguage(null)771.build()772.getLanguage();773assertEquals("null", defaulted, result);774775// language codes must be 2-8 alpha776// for forwards compatibility, 4-alpha and 5-8 alpha (registered)777// languages are accepted syntax778new BuilderILE("q", "abcdefghi", "13") { public void call() { b.setLanguage(arg); }};779780// language code validation is NOT performed, any 2-8-alpha passes781assertNotNull("2alpha", builder.setLanguage("zz").build());782assertNotNull("8alpha", builder.setLanguage("abcdefgh").build());783784// three-letter language codes are NOT canonicalized to two-letter785result = builder786.setLanguage("eng")787.build()788.getLanguage();789assertEquals("eng", "eng", result);790}791792public void testBuilderSetScript() {793// script is normalized to title case794String source = "lAtN";795String target = "Latn";796String defaulted = "";797Builder builder = new Builder();798String result = builder799.setScript(source)800.build()801.getScript();802assertEquals("script", target, result);803804// setting with empty resets805result = builder806.setScript(target)807.setScript("")808.build()809.getScript();810assertEquals("empty", defaulted, result);811812// settting with null also resets813result = builder814.setScript(target)815.setScript(null)816.build()817.getScript();818assertEquals("null", defaulted, result);819820// ill-formed script codes throw IAE821// must be 4alpha822new BuilderILE("abc", "abcde", "l3tn") { public void call() { b.setScript(arg); }};823824// script code validation is NOT performed, any 4-alpha passes825assertEquals("4alpha", "Wxyz", builder.setScript("wxyz").build().getScript());826}827828public void testBuilderSetRegion() {829// region is normalized to upper case830String source = "uS";831String target = "US";832String defaulted = "";833Builder builder = new Builder();834String result = builder835.setRegion(source)836.build()837.getCountry();838assertEquals("us", target, result);839840// setting with empty resets841result = builder842.setRegion(target)843.setRegion("")844.build()845.getCountry();846assertEquals("empty", defaulted, result);847848// setting with null also resets849result = builder850.setRegion(target)851.setRegion(null)852.build()853.getCountry();854assertEquals("null", defaulted, result);855856// ill-formed region codes throw IAE857// 2 alpha or 3 numeric858new BuilderILE("q", "abc", "12", "1234", "a3", "12a") { public void call() { b.setRegion(arg); }};859860// region code validation is NOT performed, any 2-alpha or 3-digit passes861assertEquals("2alpha", "ZZ", builder.setRegion("ZZ").build().getCountry());862assertEquals("3digit", "000", builder.setRegion("000").build().getCountry());863}864865public void testBuilderSetVariant() {866// Variant case is not normalized in lenient variant mode867String source = "NewYork";868String target = source;869String defaulted = "";870Builder builder = new Builder();871String result = builder872.setVariant(source)873.build()874.getVariant();875assertEquals("NewYork", target, result);876877result = builder878.setVariant("NeWeR_YoRkEr")879.build()880.toLanguageTag();881assertEquals("newer yorker", "und-NeWeR-YoRkEr", result);882883// subtags of variant are NOT reordered884result = builder885.setVariant("zzzzz_yyyyy_xxxxx")886.build()887.getVariant();888assertEquals("zyx", "zzzzz_yyyyy_xxxxx", result);889890// setting to empty resets891result = builder892.setVariant(target)893.setVariant("")894.build()895.getVariant();896assertEquals("empty", defaulted, result);897898// setting to null also resets899result = builder900.setVariant(target)901.setVariant(null)902.build()903.getVariant();904assertEquals("null", defaulted, result);905906// ill-formed variants throw IAE907// digit followed by 3-7 characters, or alpha followed by 4-8 characters.908new BuilderILE("abcd", "abcdefghi", "1ab", "1abcdefgh") { public void call() { b.setVariant(arg); }};909910// 4 characters is ok as long as the first is a digit911assertEquals("digit+3alpha", "1abc", builder.setVariant("1abc").build().getVariant());912913// all subfields must conform914new BuilderILE("abcde-fg") { public void call() { b.setVariant(arg); }};915}916917public void testBuilderSetExtension() {918// upper case characters are normalized to lower case919final char sourceKey = 'a';920final String sourceValue = "aB-aBcdefgh-12-12345678";921String target = "ab-abcdefgh-12-12345678";922Builder builder = new Builder();923String result = builder924.setExtension(sourceKey, sourceValue)925.build()926.getExtension(sourceKey);927assertEquals("extension", target, result);928929// setting with empty resets930result = builder931.setExtension(sourceKey, sourceValue)932.setExtension(sourceKey, "")933.build()934.getExtension(sourceKey);935assertEquals("empty", null, result);936937// setting with null also resets938result = builder939.setExtension(sourceKey, sourceValue)940.setExtension(sourceKey, null)941.build()942.getExtension(sourceKey);943assertEquals("null", null, result);944945// ill-formed extension keys throw IAE946// must be in [0-9a-ZA-Z]947new BuilderILE("$") { public void call() { b.setExtension('$', sourceValue); }};948949// each segment of value must be 2-8 alphanum950new BuilderILE("ab-cd-123456789") { public void call() { b.setExtension(sourceKey, arg); }};951952// no multiple hyphens.953new BuilderILE("ab--cd") { public void call() { b.setExtension(sourceKey, arg); }};954955// locale extension key has special handling956Locale locale = builder957.setExtension('u', "co-japanese")958.build();959assertEquals("locale extension", "japanese", locale.getUnicodeLocaleType("co"));960961// locale extension has same behavior with set locale keyword962Locale locale2 = builder963.setUnicodeLocaleKeyword("co", "japanese")964.build();965assertEquals("locales with extension", locale, locale2);966967// setting locale extension overrides all previous calls to setLocaleKeyword968Locale locale3 = builder969.setExtension('u', "xxx-nu-thai")970.build();971assertEquals("remove co", null, locale3.getUnicodeLocaleType("co"));972assertEquals("override thai", "thai", locale3.getUnicodeLocaleType("nu"));973assertEquals("override attribute", 1, locale3.getUnicodeLocaleAttributes().size());974975// setting locale keyword extends values already set by the locale extension976Locale locale4 = builder977.setUnicodeLocaleKeyword("co", "japanese")978.build();979assertEquals("extend", "japanese", locale4.getUnicodeLocaleType("co"));980assertEquals("extend", "thai", locale4.getUnicodeLocaleType("nu"));981982// locale extension subtags are reordered983result = builder984.clear()985.setExtension('u', "456-123-zz-123-yy-456-xx-789")986.build()987.toLanguageTag();988assertEquals("reorder", "und-u-123-456-xx-789-yy-456-zz-123", result);989990// multiple keyword types991result = builder992.clear()993.setExtension('u', "nu-thai-foobar")994.build()995.getUnicodeLocaleType("nu");996assertEquals("multiple types", "thai-foobar", result);997998// redundant locale extensions are ignored999result = builder1000.clear()1001.setExtension('u', "nu-thai-NU-chinese-xx-1234")1002.build()1003.toLanguageTag();1004assertEquals("duplicate keys", "und-u-nu-thai-xx-1234", result);1005}10061007public void testBuilderAddUnicodeLocaleAttribute() {1008Builder builder = new Builder();1009Locale locale = builder1010.addUnicodeLocaleAttribute("def")1011.addUnicodeLocaleAttribute("abc")1012.build();10131014Set<String> uattrs = locale.getUnicodeLocaleAttributes();1015assertEquals("number of attributes", 2, uattrs.size());1016assertTrue("attribute abc", uattrs.contains("abc"));1017assertTrue("attribute def", uattrs.contains("def"));10181019// remove attribute1020locale = builder.removeUnicodeLocaleAttribute("xxx")1021.build();10221023assertEquals("remove bogus", 2, uattrs.size());10241025// add duplicate1026locale = builder.addUnicodeLocaleAttribute("abc")1027.build();1028assertEquals("add duplicate", 2, uattrs.size());10291030// null attribute throws NPE1031new BuilderNPE("null attribute") { public void call() { b.addUnicodeLocaleAttribute(null); }};10321033// illformed attribute throws IllformedLocaleException1034new BuilderILE("invalid attribute") { public void call() { b.addUnicodeLocaleAttribute("ca"); }};1035}10361037public void testBuildersetUnicodeLocaleKeyword() {1038// Note: most behavior is tested in testBuilderSetExtension1039Builder builder = new Builder();1040Locale locale = builder1041.setUnicodeLocaleKeyword("co", "japanese")1042.setUnicodeLocaleKeyword("nu", "thai")1043.build();1044assertEquals("co", "japanese", locale.getUnicodeLocaleType("co"));1045assertEquals("nu", "thai", locale.getUnicodeLocaleType("nu"));1046assertEquals("keys", 2, locale.getUnicodeLocaleKeys().size());10471048// can clear a keyword by setting to null, others remain1049String result = builder1050.setUnicodeLocaleKeyword("co", null)1051.build()1052.toLanguageTag();1053assertEquals("empty co", "und-u-nu-thai", result);10541055// locale keyword extension goes when all keywords are gone1056result = builder1057.setUnicodeLocaleKeyword("nu", null)1058.build()1059.toLanguageTag();1060assertEquals("empty nu", "und", result);10611062// locale keywords are ordered independent of order of addition1063result = builder1064.setUnicodeLocaleKeyword("zz", "012")1065.setUnicodeLocaleKeyword("aa", "345")1066.build()1067.toLanguageTag();1068assertEquals("reordered", "und-u-aa-345-zz-012", result);10691070// null keyword throws NPE1071new BuilderNPE("keyword") { public void call() { b.setUnicodeLocaleKeyword(null, "thai"); }};10721073// well-formed keywords are two alphanum1074new BuilderILE("a", "abc") { public void call() { b.setUnicodeLocaleKeyword(arg, "value"); }};10751076// well-formed values are 3-8 alphanum1077new BuilderILE("ab", "abcdefghi") { public void call() { b.setUnicodeLocaleKeyword("ab", arg); }};1078}10791080public void testBuilderPrivateUseExtension() {1081// normalizes hyphens to underscore, case to lower1082String source = "c-B-a";1083String target = "c-b-a";1084Builder builder = new Builder();1085String result = builder1086.setExtension(Locale.PRIVATE_USE_EXTENSION, source)1087.build()1088.getExtension(Locale.PRIVATE_USE_EXTENSION);1089assertEquals("abc", target, result);10901091// multiple hyphens are ill-formed1092new BuilderILE("a--b") { public void call() { b.setExtension(Locale.PRIVATE_USE_EXTENSION, arg); }};1093}10941095public void testBuilderClear() {1096String monster = "en-latn-US-NewYork-a-bb-cc-u-co-japanese-x-z-y-x-x";1097Builder builder = new Builder();1098Locale locale = Locale.forLanguageTag(monster);1099String result = builder1100.setLocale(locale)1101.clear()1102.build()1103.toLanguageTag();1104assertEquals("clear", "und", result);1105}11061107public void testBuilderRemoveUnicodeAttribute() {1108// tested in testBuilderAddUnicodeAttribute1109}11101111public void testBuilderBuild() {1112// tested in other test methods1113}11141115public void testSerialize() {1116final Locale[] testLocales = {1117Locale.ROOT,1118new Locale("en"),1119new Locale("en", "US"),1120new Locale("en", "US", "Win"),1121new Locale("en", "US", "Win_XP"),1122new Locale("ja", "JP"),1123new Locale("ja", "JP", "JP"),1124new Locale("th", "TH"),1125new Locale("th", "TH", "TH"),1126new Locale("no", "NO"),1127new Locale("nb", "NO"),1128new Locale("nn", "NO"),1129new Locale("no", "NO", "NY"),1130new Locale("nn", "NO", "NY"),1131new Locale("he", "IL"),1132new Locale("he", "IL", "var"),1133new Locale("Language", "Country", "Variant"),1134new Locale("", "US"),1135new Locale("", "", "Java"),1136Locale.forLanguageTag("en-Latn-US"),1137Locale.forLanguageTag("zh-Hans"),1138Locale.forLanguageTag("zh-Hant-TW"),1139Locale.forLanguageTag("ja-JP-u-ca-japanese"),1140Locale.forLanguageTag("und-Hant"),1141Locale.forLanguageTag("und-a-123-456"),1142Locale.forLanguageTag("en-x-java"),1143Locale.forLanguageTag("th-TH-u-ca-buddist-nu-thai-x-lvariant-TH"),1144};11451146for (Locale locale : testLocales) {1147try {1148// write1149ByteArrayOutputStream bos = new ByteArrayOutputStream();1150ObjectOutputStream oos = new ObjectOutputStream(bos);1151oos.writeObject(locale);11521153// read1154ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());1155ObjectInputStream ois = new ObjectInputStream(bis);1156Object o = ois.readObject();11571158assertEquals("roundtrip " + locale, locale, o);1159} catch (Exception e) {1160errln(locale + " encountered exception:" + e.getLocalizedMessage());1161}1162}1163}11641165public void testDeserialize6() {1166final String TESTFILEPREFIX = "java6locale_";11671168File dataDir = null;1169String dataDirName = System.getProperty("serialized.data.dir");1170if (dataDirName == null) {1171URL resdirUrl = getClass().getClassLoader().getResource("serialized");1172if (resdirUrl != null) {1173try {1174dataDir = new File(resdirUrl.toURI());1175} catch (URISyntaxException urie) {1176}1177}1178} else {1179dataDir = new File(dataDirName);1180}11811182if (dataDir == null || !dataDir.isDirectory()) {1183errln("Could not locate the serialized test case data location");1184return;1185}11861187File[] files = dataDir.listFiles();1188for (File testfile : files) {1189if (testfile.isDirectory()) {1190continue;1191}1192String name = testfile.getName();1193if (!name.startsWith(TESTFILEPREFIX)) {1194continue;1195}1196Locale locale;1197String locStr = name.substring(TESTFILEPREFIX.length());1198if (locStr.equals("ROOT")) {1199locale = Locale.ROOT;1200} else {1201String[] fields = locStr.split("_", 3);1202String lang = fields[0];1203String country = (fields.length >= 2) ? fields[1] : "";1204String variant = (fields.length == 3) ? fields[2] : "";1205locale = new Locale(lang, country, variant);1206}12071208// deserialize1209try (FileInputStream fis = new FileInputStream(testfile);1210ObjectInputStream ois = new ObjectInputStream(fis))1211{1212Object o = ois.readObject();1213assertEquals("Deserialize Java 6 Locale " + locale, o, locale);1214} catch (Exception e) {1215errln("Exception while reading " + testfile.getAbsolutePath() + " - " + e.getMessage());1216}1217}1218}12191220public void testBug7002320() {1221// forLanguageTag() and Builder.setLanguageTag(String)1222// should add a location extension for following two cases.1223//1224// 1. language/country are "ja"/"JP" and the resolved variant (x-lvariant-*)1225// is exactly "JP" and no BCP 47 extensions are available, then add1226// a Unicode locale extension "ca-japanese".1227// 2. language/country are "th"/"TH" and the resolved variant is exactly1228// "TH" and no BCP 47 extensions are available, then add a Unicode locale1229// extension "nu-thai".1230//1231String[][] testdata = {1232{"ja-JP-x-lvariant-JP", "ja-JP-u-ca-japanese-x-lvariant-JP"}, // special case 11233{"ja-JP-x-lvariant-JP-XXX"},1234{"ja-JP-u-ca-japanese-x-lvariant-JP"},1235{"ja-JP-u-ca-gregory-x-lvariant-JP"},1236{"ja-JP-u-cu-jpy-x-lvariant-JP"},1237{"ja-x-lvariant-JP"},1238{"th-TH-x-lvariant-TH", "th-TH-u-nu-thai-x-lvariant-TH"}, // special case 21239{"th-TH-u-nu-thai-x-lvariant-TH"},1240{"en-US-x-lvariant-JP"},1241};12421243Builder bldr = new Builder();12441245for (String[] data : testdata) {1246String in = data[0];1247String expected = (data.length == 1) ? data[0] : data[1];12481249// forLanguageTag1250Locale loc = Locale.forLanguageTag(in);1251String out = loc.toLanguageTag();1252assertEquals("Language tag roundtrip by forLanguageTag with input: " + in, expected, out);12531254// setLanguageTag1255bldr.clear();1256bldr.setLanguageTag(in);1257loc = bldr.build();1258out = loc.toLanguageTag();1259assertEquals("Language tag roundtrip by Builder.setLanguageTag with input: " + in, expected, out);1260}1261}12621263public void testBug7023613() {1264String[][] testdata = {1265{"en-Latn", "en__#Latn"},1266{"en-u-ca-japanese", "en__#u-ca-japanese"},1267};12681269for (String[] data : testdata) {1270String in = data[0];1271String expected = (data.length == 1) ? data[0] : data[1];12721273Locale loc = Locale.forLanguageTag(in);1274String out = loc.toString();1275assertEquals("Empty country field with non-empty script/extension with input: " + in, expected, out);1276}1277}12781279/*1280* 7033504: (lc) incompatible behavior change for ja_JP_JP and th_TH_TH locales1281*/1282public void testBug7033504() {1283checkCalendar(new Locale("ja", "JP", "jp"), "java.util.GregorianCalendar");1284checkCalendar(new Locale("ja", "jp", "jp"), "java.util.GregorianCalendar");1285checkCalendar(new Locale("ja", "JP", "JP"), "java.util.JapaneseImperialCalendar");1286checkCalendar(new Locale("ja", "jp", "JP"), "java.util.JapaneseImperialCalendar");1287checkCalendar(Locale.forLanguageTag("en-u-ca-japanese"),1288"java.util.JapaneseImperialCalendar");12891290checkDigit(new Locale("th", "TH", "th"), '0');1291checkDigit(new Locale("th", "th", "th"), '0');1292checkDigit(new Locale("th", "TH", "TH"), '\u0e50');1293checkDigit(new Locale("th", "TH", "TH"), '\u0e50');1294checkDigit(Locale.forLanguageTag("en-u-nu-thai"), '\u0e50');1295}12961297private void checkCalendar(Locale loc, String expected) {1298Calendar cal = Calendar.getInstance(loc);1299assertEquals("Wrong calendar", expected, cal.getClass().getName());1300}13011302private void checkDigit(Locale loc, Character expected) {1303DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(loc);1304Character zero = dfs.getZeroDigit();1305assertEquals("Wrong digit zero char", expected, zero);1306}13071308///1309/// utility asserts1310///13111312private void assertTrue(String msg, boolean v) {1313if (!v) {1314errln(msg + ": expected true");1315}1316}13171318private void assertFalse(String msg, boolean v) {1319if (v) {1320errln(msg + ": expected false");1321}1322}13231324private void assertEquals(String msg, Object e, Object v) {1325if (e == null ? v != null : !e.equals(v)) {1326if (e != null) {1327e = "'" + e + "'";1328}1329if (v != null) {1330v = "'" + v + "'";1331}1332errln(msg + ": expected " + e + " but got " + v);1333}1334}13351336private void assertNotEquals(String msg, Object e, Object v) {1337if (e == null ? v == null : e.equals(v)) {1338if (e != null) {1339e = "'" + e + "'";1340}1341errln(msg + ": expected not equal " + e);1342}1343}13441345private void assertNull(String msg, Object o) {1346if (o != null) {1347errln(msg + ": expected null but got '" + o + "'");1348}1349}13501351private void assertNotNull(String msg, Object o) {1352if (o == null) {1353errln(msg + ": expected non null");1354}1355}13561357// not currently used, might get rid of exceptions from the API1358private abstract class ExceptionTest {1359private final Class<? extends Exception> exceptionClass;13601361ExceptionTest(Class<? extends Exception> exceptionClass) {1362this.exceptionClass = exceptionClass;1363}13641365public void run() {1366String failMsg = null;1367try {1368call();1369failMsg = "expected " + exceptionClass.getName() + " but no exception thrown.";1370}1371catch (Exception e) {1372if (!exceptionClass.isAssignableFrom(e.getClass())) {1373failMsg = "expected " + exceptionClass.getName() + " but caught " + e;1374}1375}1376if (failMsg != null) {1377String msg = message();1378msg = msg == null ? "" : msg + " ";1379errln(msg + failMsg);1380}1381}13821383public String message() {1384return null;1385}13861387public abstract void call();1388}13891390private abstract class ExpectNPE extends ExceptionTest {1391ExpectNPE() {1392super(NullPointerException.class);1393run();1394}1395}13961397private abstract class BuilderNPE extends ExceptionTest {1398protected final String msg;1399protected final Builder b = new Builder();14001401BuilderNPE(String msg) {1402super(NullPointerException.class);14031404this.msg = msg;14051406run();1407}14081409public String message() {1410return msg;1411}1412}14131414private abstract class ExpectIAE extends ExceptionTest {1415ExpectIAE() {1416super(IllegalArgumentException.class);1417run();1418}1419}14201421private abstract class BuilderILE extends ExceptionTest {1422protected final String[] args;1423protected final Builder b = new Builder();14241425protected String arg; // mutates during call14261427BuilderILE(String... args) {1428super(IllformedLocaleException.class);14291430this.args = args;14311432run();1433}14341435public void run() {1436for (String arg : args) {1437this.arg = arg;1438super.run();1439}1440}14411442public String message() {1443return "arg: '" + arg + "'";1444}1445}1446}144714481449