1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8167143 27 * @summary Test 28 * Timezone parsing works for all locales for default providers prefernce 29 * as well as when prefernce list is [COMPAT, CLDR], 30 * CLDR implict locales are correctly reflected, 31 * th_TH bundle is not wrongly cached in DateFormatSymbols, 32 * correct candidate locale list is retrieved for 33 * zh_Hant and zh_Hans and 34 * Implict COMPAT Locales nn-NO, nb-NO are reflected in available locales 35 * for all Providers for COMPAT. 36 * @modules java.base/sun.util.locale.provider 37 * java.base/sun.util.spi 38 * jdk.localedata 39 * @run main/othervm -Djava.locale.providers=COMPAT,CLDR Bug8167143 testTimeZone 40 * @run main/othervm Bug8167143 testTimeZone 41 * @run main/othervm -Djava.locale.providers=CLDR Bug8167143 testCldr 42 * @run main/othervm Bug8167143 testCache 43 * @run main/othervm Bug8167143 testCandidateLocales 44 * @run main/othervm -Djava.locale.providers=COMPAT Bug8167143 testCompat 45 */ 46 import java.text.ParseException; 47 import java.text.SimpleDateFormat; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.List; 51 import java.util.Locale; 52 import java.util.ResourceBundle; 53 import java.util.Set; 54 import java.util.TimeZone; 55 56 import sun.util.locale.provider.LocaleProviderAdapter; 57 import sun.util.locale.provider.LocaleProviderAdapter.Type; 58 59 public class Bug8167143 { 60 61 private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik"); 62 private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York"); 63 private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); 64 65 private static final List<Locale> CLDR_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("zh-Hans-CN"), 66 Locale.forLanguageTag("zh-Hans-SG"), 67 Locale.forLanguageTag("zh-Hant-HK"), 68 Locale.forLanguageTag("zh-Hant-TW"), 69 Locale.forLanguageTag("zh-Hant-MO")); 70 71 private static final List<Locale> COMPAT_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("nn-NO"), 72 Locale.forLanguageTag("nb-NO")); 73 /** 74 * List of candidate locales for zh_Hant 75 */ 76 private static final List<Locale> ZH_HANT_CANDLOCS = List.of( 77 Locale.forLanguageTag("zh-Hant"), 78 Locale.forLanguageTag("zh-TW"), 79 Locale.forLanguageTag("zh"), 80 Locale.ROOT); 81 /** 82 * List of candidate locales for zh_Hans 83 */ 84 private static final List<Locale> ZH_HANS_CANDLOCS = List.of( 85 Locale.forLanguageTag("zh-Hans"), 86 Locale.forLanguageTag("zh-CN"), 87 Locale.forLanguageTag("zh"), 88 Locale.ROOT); 89 main(String[] args)90 public static void main(String[] args) { 91 switch (args[0]) { 92 case "testTimeZone": 93 testTimeZoneParsing(); 94 break; 95 case "testCldr": 96 testImplicitCldrLocales(); 97 break; 98 case "testCache": 99 testDateFormatSymbolsCache(); 100 break; 101 case "testCandidateLocales": 102 testCandidateLocales(); 103 break; 104 case "testCompat": 105 testImplicitCompatLocales(); 106 break; 107 default: 108 throw new RuntimeException("no test was specified."); 109 } 110 } 111 112 /** 113 * Check that if Locale Provider Preference list is Default, or if Locale 114 * Provider Preference List is COMPAT,CLDR SimplDateFormat parsing works for 115 * all Available Locales. 116 */ testTimeZoneParsing()117 private static void testTimeZoneParsing() { 118 Set<Locale> locales = Set.of(Locale.forLanguageTag("zh-hant"), new Locale("no", "NO", "NY")); 119 // Set<Locale> locales = Set.of(Locale.getAvailableLocales()); 120 locales.forEach((locale) -> { 121 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", locale); 122 for (final TimeZone tz : new TimeZone[]{REYKJAVIK, GMT, NEW_YORK}) { 123 try { 124 sdf.parse("2000/02/10 " + tz.getDisplayName(locale)); 125 } catch (ParseException e) { 126 throw new RuntimeException("TimeZone Parsing failed with Locale " 127 + locale + " for TimeZone " + tz.getDisplayName(), e); 128 } 129 } 130 }); 131 } 132 133 /** 134 * Check that locales implicitly supported from CLDR are reflected in output 135 * from getAvailbleLocales() for each bundle. 136 * 137 */ testImplicitCldrLocales()138 private static void testImplicitCldrLocales() { 139 LocaleProviderAdapter cldr = LocaleProviderAdapter.forType(Type.CLDR); 140 checkPresenceCldr("CurrencyNameProvider", 141 cldr.getCurrencyNameProvider().getAvailableLocales()); 142 checkPresenceCldr("LocaleNameProvider", 143 cldr.getLocaleNameProvider().getAvailableLocales()); 144 checkPresenceCldr("TimeZoneNameProvider", 145 cldr.getTimeZoneNameProvider().getAvailableLocales()); 146 checkPresenceCldr("CalendarDataProvider", 147 cldr.getCalendarDataProvider().getAvailableLocales()); 148 checkPresenceCldr("CalendarNameProvider", 149 cldr.getCalendarProvider().getAvailableLocales()); 150 } 151 checkPresenceCldr(String testName, Locale[] got)152 private static void checkPresenceCldr(String testName, Locale[] got) { 153 List<Locale> gotLocalesList = Arrays.asList(got); 154 List<Locale> gotList = new ArrayList<>(gotLocalesList); 155 if (!testName.equals("TimeZoneNameProvider")) { 156 if (!gotList.removeAll(CLDR_IMPLICIT_LOCS)) { 157 // check which locale are not present in retrievedLocales List. 158 List<Locale> expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS); 159 expectedLocales.removeAll(gotList); 160 throw new RuntimeException("Locales those not correctly reflected are " 161 + expectedLocales + " for test " + testName); 162 } 163 } else { 164 // check one extra locale zh_HK for TimeZoneNameProvider 165 Locale zh_HK = Locale.forLanguageTag("zh-HK"); 166 if (!gotList.removeAll(CLDR_IMPLICIT_LOCS) && gotList.remove(zh_HK)) { 167 //check which locale are not present in retrievedLocales List 168 List<Locale> expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS); 169 expectedLocales.add(zh_HK); 170 expectedLocales.removeAll(gotList); 171 throw new RuntimeException("Locales those not correctly reflected are " 172 + expectedLocales + " for test " + testName); 173 } 174 } 175 } 176 177 /** 178 * Check that if Locale Provider Preference list is default and if 179 * SimpleDateFormat instance for th-TH-TH is created first, then JRE bundle 180 * for th-TH should not be cached in cache of DateFormatSymbols class. 181 */ testDateFormatSymbolsCache()182 private static void testDateFormatSymbolsCache() { 183 Locale th_TH_TH = new Locale("th", "TH", "TH"); 184 Locale th_TH = new Locale("th", "TH"); 185 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", th_TH_TH); 186 String[][] thTHTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings(); 187 String[][] thTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings(); 188 if (Arrays.equals(thTHTHZoneStrings, thTHZoneStrings)) { 189 throw new RuntimeException("th_TH bundle still cached with DateFormatSymbols" 190 + "cache for locale " + th_TH 191 ); 192 } 193 } 194 195 /** 196 * Check that candidate locales list retrieved for zh__Hant and for zh__Hans 197 * do not have first candidate locale as zh_TW_Hant and zh_CN_Hans 198 * respectively. 199 */ testCandidateLocales()200 private static void testCandidateLocales() { 201 ResourceBundle.Control Control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); 202 Locale zh_Hant = Locale.forLanguageTag("zh-Hant"); 203 Locale zh_Hans = Locale.forLanguageTag("zh-Hans"); 204 List<Locale> zhHantCandidateLocs = Control.getCandidateLocales("", zh_Hant); 205 List<Locale> zhHansCandidateLocs = Control.getCandidateLocales("", zh_Hans); 206 if (!zhHantCandidateLocs.equals(ZH_HANT_CANDLOCS)) { 207 reportDifference(zhHantCandidateLocs, ZH_HANT_CANDLOCS, "zh_Hant"); 208 209 } 210 if (!zhHansCandidateLocs.equals(ZH_HANS_CANDLOCS)) { 211 reportDifference(zhHansCandidateLocs, ZH_HANS_CANDLOCS, "zh_Hans"); 212 213 } 214 } 215 reportDifference(List<Locale> got, List<Locale> expected, String locale)216 private static void reportDifference(List<Locale> got, List<Locale> expected, String locale) { 217 List<Locale> retrievedList = new ArrayList<>(got); 218 List<Locale> expectedList = new ArrayList<>(expected); 219 retrievedList.removeAll(expectedList); 220 expectedList.removeAll(retrievedList); 221 if ((retrievedList.size() > 0) && (expectedList.size() > 0)) { 222 throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList 223 + " and missing candidate locales " + expectedList 224 + "for locale " + locale); 225 } 226 if ((retrievedList.size() > 0)) { 227 throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList 228 + "for locale " + locale); 229 } 230 if ((expectedList.size() > 0)) { 231 throw new RuntimeException(" retrievedList contain extra candidate locales " + expectedList 232 + "for locale " + locale); 233 } 234 } 235 236 /** 237 * checks that locales nn-NO and nb-NO should be present in list of supported locales for 238 * all Providers for COMPAT. 239 */ testImplicitCompatLocales()240 private static void testImplicitCompatLocales() { 241 LocaleProviderAdapter jre = LocaleProviderAdapter.forJRE(); 242 checkPresenceCompat("BreakIteratorProvider", 243 jre.getBreakIteratorProvider().getAvailableLocales()); 244 checkPresenceCompat("CollatorProvider", 245 jre.getCollatorProvider().getAvailableLocales()); 246 checkPresenceCompat("DateFormatProvider", 247 jre.getDateFormatProvider().getAvailableLocales()); 248 checkPresenceCompat("DateFormatSymbolsProvider", 249 jre.getDateFormatSymbolsProvider().getAvailableLocales()); 250 checkPresenceCompat("DecimalFormatSymbolsProvider", 251 jre.getDecimalFormatSymbolsProvider().getAvailableLocales()); 252 checkPresenceCompat("NumberFormatProvider", 253 jre.getNumberFormatProvider().getAvailableLocales()); 254 checkPresenceCompat("CurrencyNameProvider", 255 jre.getCurrencyNameProvider().getAvailableLocales()); 256 checkPresenceCompat("LocaleNameProvider", 257 jre.getLocaleNameProvider().getAvailableLocales()); 258 checkPresenceCompat("TimeZoneNameProvider", 259 jre.getTimeZoneNameProvider().getAvailableLocales()); 260 checkPresenceCompat("CalendarDataProvider", 261 jre.getCalendarDataProvider().getAvailableLocales()); 262 checkPresenceCompat("CalendarNameProvider", 263 jre.getCalendarNameProvider().getAvailableLocales()); 264 checkPresenceCompat("CalendarProvider", 265 jre.getCalendarProvider().getAvailableLocales()); 266 } 267 checkPresenceCompat(String testName, Locale[] got)268 private static void checkPresenceCompat(String testName, Locale[] got) { 269 List<Locale> gotLocalesList = Arrays.asList(got); 270 List<Locale> gotList = new ArrayList<>(gotLocalesList); 271 if (!gotList.removeAll(COMPAT_IMPLICIT_LOCS)) { 272 // check which Implicit locale are not present in retrievedLocales List. 273 List<Locale> implicitLocales = new ArrayList<>(COMPAT_IMPLICIT_LOCS); 274 implicitLocales.removeAll(gotList); 275 throw new RuntimeException("Locales those not correctly reflected are " 276 + implicitLocales + " for test " + testName); 277 } 278 } 279 } 280