1 /* 2 ******************************************************************************* 3 * Copyright (C) 2006-2015, Google, International Business Machines Corporation * 4 * and others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 8 package com.ibm.icu.dev.test.format; 9 10 import java.text.ParsePosition; 11 import java.util.Collection; 12 import java.util.Date; 13 import java.util.HashSet; 14 import java.util.Iterator; 15 import java.util.LinkedHashMap; 16 import java.util.LinkedHashSet; 17 import java.util.List; 18 import java.util.Locale; 19 import java.util.Map; 20 import java.util.Random; 21 import java.util.Set; 22 23 import com.ibm.icu.dev.test.TestFmwk; 24 import com.ibm.icu.impl.PatternTokenizer; 25 import com.ibm.icu.impl.Utility; 26 import com.ibm.icu.text.DateFormat; 27 import com.ibm.icu.text.DateTimePatternGenerator; 28 import com.ibm.icu.text.DateTimePatternGenerator.FormatParser; 29 import com.ibm.icu.text.DateTimePatternGenerator.VariableField; 30 import com.ibm.icu.text.SimpleDateFormat; 31 import com.ibm.icu.text.UTF16; 32 import com.ibm.icu.text.UnicodeSet; 33 import com.ibm.icu.util.Calendar; 34 import com.ibm.icu.util.GregorianCalendar; 35 import com.ibm.icu.util.SimpleTimeZone; 36 import com.ibm.icu.util.TimeZone; 37 import com.ibm.icu.util.ULocale; 38 39 public class DateTimeGeneratorTest extends TestFmwk { 40 public static boolean GENERATE_TEST_DATA; 41 static { 42 try { 43 GENERATE_TEST_DATA = System.getProperty("GENERATE_TEST_DATA") != null; 44 } catch (SecurityException e) { 45 GENERATE_TEST_DATA = false; 46 } 47 }; 48 public static int RANDOM_COUNT = 1000; 49 public static boolean DEBUG = false; 50 main(String[] args)51 public static void main(String[] args) throws Exception { 52 new DateTimeGeneratorTest().run(args); 53 } 54 TestSimple()55 public void TestSimple() { 56 // some simple use cases 57 ULocale locale = ULocale.GERMANY; 58 TimeZone zone = TimeZone.getTimeZone("Europe/Paris"); 59 60 // make from locale 61 DateTimePatternGenerator gen = DateTimePatternGenerator.getInstance(locale); 62 SimpleDateFormat format = new SimpleDateFormat(gen.getBestPattern("MMMddHmm"), locale); 63 format.setTimeZone(zone); 64 assertEquals("simple format: MMMddHmm", "14. Okt., 08:58", format.format(sampleDate)); 65 // (a generator can be built from scratch, but that is not a typical use case) 66 67 // modify the generator by adding patterns 68 DateTimePatternGenerator.PatternInfo returnInfo = new DateTimePatternGenerator.PatternInfo(); 69 gen.addPattern("d'. von' MMMM", true, returnInfo); 70 // the returnInfo is mostly useful for debugging problem cases 71 format.applyPattern(gen.getBestPattern("MMMMdHmm")); 72 assertEquals("modified format: MMMdHmm", "14. von Oktober, 08:58", format.format(sampleDate)); 73 74 // get a pattern and modify it 75 format = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale); 76 format.setTimeZone(zone); 77 String pattern = format.toPattern(); 78 assertEquals("full-date", "Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\u00E4ische Sommerzeit", format.format(sampleDate)); 79 80 // modify it to change the zone. 81 String newPattern = gen.replaceFieldTypes(pattern, "vvvv"); 82 format.applyPattern(newPattern); 83 assertEquals("full-date: modified zone", "Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\u00E4ische Zeit", format.format(sampleDate)); 84 85 // add test of basic cases 86 87 //lang YYYYMMM MMMd MMMdhmm hmm hhmm Full Date-Time 88 // en Mar 2007 Mar 4 6:05 PM Mar 4 6:05 PM 06:05 PM Sunday, March 4, 2007 6:05:05 PM PT 89 DateTimePatternGenerator enGen = DateTimePatternGenerator.getInstance(ULocale.ENGLISH); 90 TimeZone enZone = TimeZone.getTimeZone("Etc/GMT"); 91 SimpleDateFormat enFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, ULocale.ENGLISH); 92 enFormat.setTimeZone(enZone); 93 String[][] tests = { 94 {"yyyyMMMdd", "Oct 14, 1999"}, 95 {"yyyyqqqq", "4th quarter 1999"}, 96 {"yMMMdd", "Oct 14, 1999"}, 97 {"EyyyyMMMdd", "Thu, Oct 14, 1999"}, 98 {"yyyyMMdd", "10/14/1999"}, 99 {"yyyyMMM", "Oct 1999"}, 100 {"yyyyMM", "10/1999"}, 101 {"yyMM", "10/99"}, 102 {"yMMMMMd", "O 14, 1999"}, // narrow format 103 {"EEEEEMMMMMd", "T, O 14"}, // narrow format 104 {"MMMd", "Oct 14"}, 105 {"MMMdhmm", "Oct 14, 6:58 AM"}, 106 {"EMMMdhmms", "Thu, Oct 14, 6:58:59 AM"}, 107 {"MMdhmm", "10/14, 6:58 AM"}, 108 {"EEEEMMMdhmms", "Thursday, Oct 14, 6:58:59 AM"}, 109 {"yyyyMMMddhhmmss", "Oct 14, 1999, 6:58:59 AM"}, // (fixed expected result per ticket 6872<-7180) 110 {"EyyyyMMMddhhmmss", "Thu, Oct 14, 1999, 6:58:59 AM"}, // (fixed expected result per ticket 6872<-7180) 111 {"hmm", "6:58 AM"}, 112 {"hhmm", "6:58 AM"}, // (fixed expected result per ticket 6872<-7180) 113 {"hhmmVVVV", "6:58 AM GMT"}, // (fixed expected result per ticket 6872<-7180) 114 }; 115 for (int i = 0; i < tests.length; ++i) { 116 final String testSkeleton = tests[i][0]; 117 String pat = enGen.getBestPattern(testSkeleton); 118 enFormat.applyPattern(pat); 119 String formattedDate = enFormat.format(sampleDate); 120 assertEquals("Testing skeleton '" + testSkeleton + "' with " + sampleDate, tests[i][1], formattedDate); 121 } 122 } 123 TestRoot()124 public void TestRoot() { 125 DateTimePatternGenerator rootGen = DateTimePatternGenerator.getInstance(ULocale.ROOT); 126 SimpleDateFormat rootFormat = new SimpleDateFormat(rootGen.getBestPattern("yMdHms"), ULocale.ROOT); 127 rootFormat.setTimeZone(gmt); 128 // *** expected result should be "1999-10-14 6:58:59" with current data, changed test temporarily to match current result, needs investigation 129 assertEquals("root format: yMdHms", "1999-10-14 06:58:59", rootFormat.format(sampleDate)); 130 } 131 TestEmpty()132 public void TestEmpty() { 133 // now nothing 134 DateTimePatternGenerator nullGen = DateTimePatternGenerator.getEmptyInstance(); 135 SimpleDateFormat format = new SimpleDateFormat(nullGen.getBestPattern("yMdHms"), ULocale.ROOT); 136 TimeZone rootZone = TimeZone.getTimeZone("Etc/GMT"); 137 format.setTimeZone(rootZone); 138 } 139 TestPatternParser()140 public void TestPatternParser() { 141 StringBuffer buffer = new StringBuffer(); 142 PatternTokenizer pp = new PatternTokenizer() 143 .setIgnorableCharacters(new UnicodeSet("[-]")) 144 .setSyntaxCharacters(new UnicodeSet("[a-zA-Z]")) 145 .setEscapeCharacters(new UnicodeSet("[b#]")) 146 .setUsingQuote(true); 147 logln("Using Quote"); 148 for (int i = 0; i < patternTestData.length; ++i) { 149 String patternTest = (String) patternTestData[i]; 150 CheckPattern(buffer, pp, patternTest); 151 } 152 String[] randomSet = {"abcdef", "$12!@#-", "'\\"}; 153 for (int i = 0; i < RANDOM_COUNT; ++i) { 154 String patternTest = getRandomString(randomSet, 0, 10); 155 CheckPattern(buffer, pp, patternTest); 156 } 157 logln("Using Backslash"); 158 pp.setUsingQuote(false).setUsingSlash(true); 159 for (int i = 0; i < patternTestData.length; ++i) { 160 String patternTest = (String) patternTestData[i]; 161 CheckPattern(buffer, pp, patternTest); 162 } 163 for (int i = 0; i < RANDOM_COUNT; ++i) { 164 String patternTest = getRandomString(randomSet, 0, 10); 165 CheckPattern(buffer, pp, patternTest); 166 } 167 } 168 169 Random random = new java.util.Random(-1); 170 getRandomString(String[] randomList, int minLen, int maxLen)171 private String getRandomString(String[] randomList, int minLen, int maxLen) { 172 StringBuffer result = new StringBuffer(); 173 int len = random.nextInt(maxLen + 1 - minLen) + minLen; 174 for (int i = minLen; i < len; ++ i) { 175 String source = randomList[random.nextInt(randomList.length)]; // don't bother with surrogates 176 char ch = source.charAt(random.nextInt(source.length())); 177 UTF16.append(result, ch); 178 } 179 return result.toString(); 180 } 181 CheckPattern(StringBuffer buffer, PatternTokenizer pp, String patternTest)182 private void CheckPattern(StringBuffer buffer, PatternTokenizer pp, String patternTest) { 183 pp.setPattern(patternTest); 184 if (DEBUG && isVerbose()) { 185 showItems(buffer, pp, patternTest); 186 } 187 String normalized = pp.setStart(0).normalize(); 188 logln("input:\t<" + patternTest + ">" + "\tnormalized:\t<" + normalized + ">"); 189 String doubleNormalized = pp.setPattern(normalized).normalize(); 190 if (!normalized.equals(doubleNormalized)) { 191 errln("Normalization not idempotent:\t" + patternTest + "\tnormalized: " + normalized + "\tnormalized2: " + doubleNormalized); 192 // allow for debugging at the point of failure 193 if (DEBUG) { 194 pp.setPattern(patternTest); 195 normalized = pp.setStart(0).normalize(); 196 pp.setPattern(normalized); 197 showItems(buffer, pp, normalized); 198 doubleNormalized = pp.normalize(); 199 } 200 } 201 } 202 showItems(StringBuffer buffer, PatternTokenizer pp, String patternTest)203 private void showItems(StringBuffer buffer, PatternTokenizer pp, String patternTest) { 204 logln("input:\t<" + patternTest + ">"); 205 while (true) { 206 buffer.setLength(0); 207 int status = pp.next(buffer); 208 if (status == PatternTokenizer.DONE) break; 209 String lit = ""; 210 if (status != PatternTokenizer.SYNTAX ) { 211 lit = "\t<" + pp.quoteLiteral(buffer) + ">"; 212 } 213 logln("\t" + statusName[status] + "\t<" + buffer + ">" + lit); 214 } 215 } 216 217 static final String[] statusName = {"DONE", "SYNTAX", "LITERAL", "BROKEN_QUOTE", "BROKEN_ESCAPE", "UNKNOWN"}; 218 TestBasic()219 public void TestBasic() { 220 ULocale uLocale = null; 221 DateTimePatternGenerator dtfg = null; 222 Date date = null; 223 for (int i = 0; i < dateTestData.length; ++i) { 224 if (dateTestData[i] instanceof ULocale) { 225 uLocale = (ULocale) dateTestData[i]; 226 dtfg = DateTimePatternGenerator.getInstance(uLocale); 227 if (GENERATE_TEST_DATA) logln("new ULocale(\"" + uLocale.toString() + "\"),"); 228 } else if (dateTestData[i] instanceof Date) { 229 date = (Date) dateTestData[i]; 230 if (GENERATE_TEST_DATA) logln("new Date(" + date.getTime()+ "L),"); 231 } else if (dateTestData[i] instanceof String) { 232 String testSkeleton = (String) dateTestData[i]; 233 String pattern = dtfg.getBestPattern(testSkeleton); 234 SimpleDateFormat sdf = new SimpleDateFormat(pattern, uLocale); 235 String formatted = sdf.format(date); 236 if (GENERATE_TEST_DATA) logln("new String[] {\"" + testSkeleton + "\", \"" + Utility.escape(formatted) + "\"},"); 237 //logln(uLocale + "\t" + testSkeleton + "\t" + pattern + "\t" + sdf.format(date)); 238 } else { 239 String[] testPair = (String[]) dateTestData[i]; 240 String testSkeleton = testPair[0]; 241 String testFormatted = testPair[1]; 242 String pattern = dtfg.getBestPattern(testSkeleton); 243 SimpleDateFormat sdf = new SimpleDateFormat(pattern, uLocale); 244 String formatted = sdf.format(date); 245 if (GENERATE_TEST_DATA) { 246 logln("new String[] {\"" + testSkeleton + "\", \"" + Utility.escape(formatted) + "\"},"); 247 } else if (!formatted.equals(testFormatted)) { 248 errln(uLocale + "\tformatted string doesn't match test case: " + testSkeleton + "\t generated: " + pattern + "\t expected: " + testFormatted + "\t got: " + formatted); 249 if (true) { // debug 250 pattern = dtfg.getBestPattern(testSkeleton); 251 sdf = new SimpleDateFormat(pattern, uLocale); 252 formatted = sdf.format(date); 253 } 254 } 255 //logln(uLocale + "\t" + testSkeleton + "\t" + pattern + "\t" + sdf.format(date)); 256 } 257 } 258 } 259 260 static final Object[] patternTestData = { 261 "'$f''#c", 262 "'' 'a", 263 "'.''.'", 264 "\\u0061\\\\", 265 "mm.dd 'dd ' x", 266 "'' ''", 267 }; 268 269 // can be generated by using GENERATE_TEST_DATA. Must be reviewed before adding 270 static final Object[] dateTestData = { 271 new Date(916300739123L), // 1999-01-13T23:58:59.123,0-0800 272 273 new ULocale("en_US"), 274 new String[] {"yM", "1/1999"}, 275 new String[] {"yMMM", "Jan 1999"}, 276 new String[] {"yMd", "1/13/1999"}, 277 new String[] {"yMMMd", "Jan 13, 1999"}, 278 new String[] {"Md", "1/13"}, 279 new String[] {"MMMd", "Jan 13"}, 280 new String[] {"MMMMd", "January 13"}, 281 new String[] {"yQQQ", "Q1 1999"}, 282 new String[] {"hhmm", "11:58 PM"}, 283 new String[] {"HHmm", "23:58"}, 284 new String[] {"jjmm", "11:58 PM"}, 285 new String[] {"mmss", "58:59"}, 286 new String[] {"yyyyMMMM", "January 1999"}, // (new item for testing 6872<-5702) 287 new String[] {"MMMEd", "Wed, Jan 13"}, 288 new String[] {"Ed", "13 Wed"}, 289 new String[] {"jmmssSSS", "11:58:59.123 PM"}, 290 new String[] {"JJmm", "11:58"}, 291 292 new ULocale("en_US@calendar=japanese"), // (new locale for testing ticket 6872<-5702) 293 new String[] {"yM", "1/11 H"}, 294 new String[] {"yMMM", "Jan 11 Heisei"}, 295 new String[] {"yMd", "1/13/11 H"}, 296 new String[] {"yMMMd", "Jan 13, 11 Heisei"}, 297 new String[] {"Md", "1/13"}, 298 new String[] {"MMMd", "Jan 13"}, 299 new String[] {"MMMMd", "January 13"}, 300 new String[] {"yQQQ", "Q1 11 Heisei"}, 301 new String[] {"hhmm", "11:58 PM"}, 302 new String[] {"HHmm", "23:58"}, 303 new String[] {"jjmm", "11:58 PM"}, 304 new String[] {"mmss", "58:59"}, 305 new String[] {"yyyyMMMM", "January 11 Heisei"}, 306 new String[] {"MMMEd", "Wed, Jan 13"}, 307 new String[] {"Ed", "13 Wed"}, 308 new String[] {"jmmssSSS", "11:58:59.123 PM"}, 309 new String[] {"JJmm", "11:58"}, 310 311 new ULocale("de_DE"), 312 new String[] {"yM", "1.1999"}, 313 new String[] {"yMMM", "Jan. 1999"}, 314 new String[] {"yMd", "13.1.1999"}, 315 new String[] {"yMMMd", "13. Jan. 1999"}, 316 new String[] {"Md", "13.1."}, // 13.1 317 new String[] {"MMMd", "13. Jan."}, 318 new String[] {"MMMMd", "13. Januar"}, 319 new String[] {"yQQQ", "Q1 1999"}, 320 new String[] {"hhmm", "11:58 nachm."}, 321 new String[] {"HHmm", "23:58"}, 322 new String[] {"jjmm", "23:58"}, 323 new String[] {"mmss", "58:59"}, 324 new String[] {"yyyyMMMM", "Januar 1999"}, // (new item for testing 6872<-5702) 325 new String[] {"MMMEd", "Mi., 13. Jan."}, 326 new String[] {"Ed", "Mi., 13."}, 327 new String[] {"jmmssSSS", "23:58:59,123"}, 328 new String[] {"JJmm", "23:58"}, 329 330 new ULocale("fi"), 331 new String[] {"yM", "1.1999"}, // (fixed expected result per ticket 6872<-6626) 332 new String[] {"yMMM", "tammi 1999"}, // (fixed expected result per ticket 6872<-7007) 333 new String[] {"yMd", "13.1.1999"}, 334 new String[] {"yMMMd", "13. tammikuuta 1999"}, 335 new String[] {"Md", "13.1."}, 336 new String[] {"MMMd", "13. tammikuuta"}, 337 new String[] {"MMMMd", "13. tammikuuta"}, 338 new String[] {"yQQQ", "1. nelj. 1999"}, 339 new String[] {"hhmm", "11.58 ip."}, 340 new String[] {"HHmm", "23.58"}, 341 new String[] {"jjmm", "23.58"}, 342 new String[] {"mmss", "58.59"}, 343 new String[] {"yyyyMMMM", "tammikuu 1999"}, // (new item for testing 6872<-5702,7007) 344 new String[] {"MMMEd", "ke 13. tammikuuta"}, 345 new String[] {"Ed", "ke 13."}, 346 new String[] {"jmmssSSS", "23.58.59,123"}, 347 new String[] {"JJmm", "23.58"}, 348 349 new ULocale("es"), 350 new String[] {"yM", "1/1999"}, 351 new String[] {"yMMM", "ene. 1999"}, 352 new String[] {"yMd", "13/1/1999"}, 353 new String[] {"yMMMd", "13 ene. 1999"}, 354 new String[] {"Md", "13/1"}, 355 new String[] {"MMMd", "13 ene."}, 356 new String[] {"MMMMd", "13 de enero"}, 357 new String[] {"yQQQ", "T1 1999"}, 358 new String[] {"hhmm", "11:58 p. m."}, 359 new String[] {"HHmm", "23:58"}, 360 new String[] {"jjmm", "23:58"}, 361 new String[] {"mmss", "58:59"}, 362 new String[] {"yyyyMMMM", "enero de 1999"}, 363 new String[] {"MMMEd", "mi\u00E9., 13 ene."}, 364 new String[] {"Ed", "mi\u00E9. 13"}, 365 new String[] {"jmmssSSS", "23:58:59,123"}, 366 new String[] {"JJmm", "23:58"}, 367 368 new ULocale("ja"), // (new locale for testing ticket 6872<-6626) 369 new String[] {"yM", "1999/1"}, 370 new String[] {"yMMM", "1999\u5E741\u6708"}, 371 new String[] {"yMd", "1999/1/13"}, 372 new String[] {"yMMMd", "1999\u5E741\u670813\u65E5"}, 373 new String[] {"Md", "1/13"}, 374 new String[] {"MMMd", "1\u670813\u65E5"}, 375 new String[] {"MMMMd", "1\u670813\u65E5"}, 376 new String[] {"yQQQ", "1999/Q1"}, 377 new String[] {"hhmm", "\u5348\u5F8C11:58"}, 378 new String[] {"HHmm", "23:58"}, 379 new String[] {"jjmm", "23:58"}, 380 new String[] {"mmss", "58:59"}, 381 new String[] {"yyyyMMMM", "1999\u5E741\u6708"}, // (new item for testing 6872<-5702) 382 new String[] {"MMMEd", "1\u670813\u65E5(\u6C34)"}, 383 new String[] {"Ed", "13\u65E5(\u6C34)"}, 384 new String[] {"jmmssSSS", "23:58:59.123"}, 385 new String[] {"JJmm", "23:58"}, 386 387 new ULocale("ja@calendar=japanese"), // (new locale for testing ticket 6872<-5702) 388 new String[] {"yM", "\u5E73\u621011/1"}, 389 new String[] {"yMMM", "\u5E73\u621011\u5E741\u6708"}, 390 new String[] {"yMd", "\u5E73\u621011/1/13"}, 391 new String[] {"yMMMd", "\u5E73\u621011\u5E741\u670813\u65E5"}, 392 new String[] {"Md", "1/13"}, 393 new String[] {"MMMd", "1\u670813\u65E5"}, 394 new String[] {"MMMMd", "1\u670813\u65E5"}, 395 new String[] {"yQQQ", "\u5E73\u621011/Q1"}, 396 new String[] {"hhmm", "\u5348\u5F8C11:58"}, 397 new String[] {"HHmm", "23:58"}, 398 new String[] {"jjmm", "23:58"}, 399 new String[] {"mmss", "58:59"}, 400 new String[] {"yyyyMMMM", "\u5E73\u621011\u5E741\u6708"}, 401 new String[] {"MMMEd", "1\u670813\u65E5(\u6C34)"}, 402 new String[] {"Ed", "13\u65E5(\u6C34)"}, 403 new String[] {"jmmssSSS", "23:58:59.123"}, 404 new String[] {"JJmm", "23:58"}, 405 406 new ULocale("zh_Hans_CN"), 407 new String[] {"yM", "1999\u5E741\u6708"}, 408 new String[] {"yMMM", "1999\u5E741\u6708"}, // (fixed expected result per ticket 6872<-6626) 409 new String[] {"yMd", "1999/1/13"}, 410 new String[] {"yMMMd", "1999\u5E741\u670813\u65E5"}, // (fixed expected result per ticket 6872<-6626) 411 new String[] {"Md", "1/13"}, 412 new String[] {"MMMd", "1\u670813\u65E5"}, // (fixed expected result per ticket 6872<-6626) 413 new String[] {"MMMMd", "1\u670813\u65E5"}, 414 new String[] {"yQQQ", "1999\u5E74\u7B2C1\u5B63\u5EA6"}, 415 new String[] {"hhmm", "\u4E0B\u534811:58"}, 416 new String[] {"HHmm", "23:58"}, 417 new String[] {"jjmm", "\u4E0B\u534811:58"}, 418 new String[] {"mmss", "58:59"}, 419 new String[] {"yyyyMMMM", "1999\u5E741\u6708"}, // (new item for testing 6872<-5702) 420 new String[] {"MMMEd", "1\u670813\u65E5\u5468\u4E09"}, 421 new String[] {"Ed", "13\u65E5\u5468\u4E09"}, 422 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"}, 423 new String[] {"JJmm", "11:58"}, 424 425 new ULocale("zh_TW@calendar=roc"), // (new locale for testing ticket 6872<-5702) 426 new String[] {"yM", "\u6C11\u570B88/1"}, 427 new String[] {"yMMM", "\u6C11\u570B88\u5E741\u6708"}, 428 new String[] {"yMd", "\u6C11\u570B88/1/13"}, 429 new String[] {"yMMMd", "\u6C11\u570B88\u5E741\u670813\u65E5"}, 430 new String[] {"Md", "1/13"}, 431 new String[] {"MMMd", "1\u670813\u65E5"}, 432 new String[] {"MMMMd", "1\u670813\u65E5"}, 433 new String[] {"yQQQ", "\u6C11\u570B88\u5E741\u5B63"}, 434 new String[] {"hhmm", "\u4E0B\u534811:58"}, 435 new String[] {"HHmm", "23:58"}, 436 new String[] {"jjmm", "\u4E0B\u534811:58"}, 437 new String[] {"mmss", "58:59"}, 438 new String[] {"yyyyMMMM", "\u6C11\u570B88\u5E741\u6708"}, 439 new String[] {"MMMEd", "1\u670813\u65E5\u9031\u4E09"}, 440 new String[] {"Ed", "13\u65E5\uFF08\u9031\u4E09\uFF09"}, 441 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"}, 442 new String[] {"JJmm", "11:58"}, 443 444 new ULocale("ru"), 445 new String[] {"yM", "01.1999"}, 446 new String[] {"yMMM", "\u044F\u043D\u0432. 1999"}, 447 new String[] {"yMd", "13.01.1999"}, 448 new String[] {"yMMMd", "13 \u044F\u043D\u0432. 1999 \u0433."}, 449 new String[] {"Md", "13.01"}, 450 new String[] {"MMMd", "13 \u044F\u043D\u0432."}, 451 new String[] {"MMMMd", "13 \u044F\u043D\u0432\u0430\u0440\u044F"}, 452 new String[] {"yQQQ", "1-\u0439 \u043A\u0432. 1999 \u0433."}, 453 new String[] {"hhmm", "11:58 PM"}, 454 new String[] {"HHmm", "23:58"}, 455 new String[] {"jjmm", "23:58"}, 456 new String[] {"mmss", "58:59"}, 457 new String[] {"yyyyMMMM", "\u044F\u043D\u0432\u0430\u0440\u044C 1999"}, 458 new String[] {"MMMEd", "\u0421\u0440, 13 \u044F\u043D\u0432."}, 459 new String[] {"Ed", "\u0421\u0440, 13"}, 460 new String[] {"jmmssSSS", "23:58:59,123"}, 461 new String[] {"JJmm", "23:58"}, 462 463 new ULocale("zh@calendar=chinese"), 464 new String[] {"yM", "1998\u620A\u5BC5\u5E74\u51AC\u6708"}, 465 new String[] {"yMMM", "1998\u620A\u5BC5\u5E74\u51AC\u6708"}, 466 new String[] {"yMd", "1998\u5E74\u51AC\u670826"}, 467 new String[] {"yMMMd", "1998\u5E74\u51AC\u670826"}, 468 new String[] {"Md", "11-26"}, 469 new String[] {"MMMd", "\u51AC\u670826\u65E5"}, 470 new String[] {"MMMMd", "\u51AC\u670826\u65E5"}, 471 new String[] {"yQQQ", "1998\u620A\u5BC5\u5E74\u7B2C\u56DB\u5B63\u5EA6"}, 472 new String[] {"hhmm", "\u4E0B\u534811:58"}, 473 new String[] {"HHmm", "23:58"}, 474 new String[] {"jjmm", "\u4E0B\u534811:58"}, 475 new String[] {"mmss", "58:59"}, 476 new String[] {"yyyyMMMM", "1998\u620A\u5BC5\u5E74\u51AC\u6708"}, 477 new String[] {"MMMEd", "\u51AC\u670826\u65E5\u5468\u4E09"}, 478 new String[] {"Ed", "26\u65E5\u5468\u4E09"}, 479 new String[] {"jmmssSSS", "\u4E0B\u534811:58:59.123"}, 480 new String[] {"JJmm", "11:58"}, 481 }; 482 DayMonthTest()483 public void DayMonthTest() { 484 final ULocale locale = ULocale.FRANCE; 485 486 // set up the generator 487 DateTimePatternGenerator dtpgen 488 = DateTimePatternGenerator.getInstance(locale); 489 490 // get a pattern for an abbreviated month and day 491 final String pattern = dtpgen.getBestPattern("MMMd"); 492 SimpleDateFormat formatter = new SimpleDateFormat(pattern, locale); 493 494 // use it to format (or parse) 495 String formatted = formatter.format(new Date()); 496 logln("formatted=" + formatted); 497 // for French, the result is "13 sept." 498 } 499 TestOrdering()500 public void TestOrdering() { 501 ULocale[] locales = ULocale.getAvailableLocales(); 502 for (int i = 0; i < locales.length; ++i) { 503 for (int style1 = DateFormat.FULL; style1 <= DateFormat.SHORT; ++style1) { 504 for (int style2 = DateFormat.FULL; style2 < style1; ++style2) { 505 checkCompatible(style1, style2, locales[i]); 506 } 507 } 508 } 509 } 510 TestReplacingZoneString()511 public void TestReplacingZoneString() { 512 Date testDate = new Date(); 513 TimeZone testTimeZone = TimeZone.getTimeZone("America/New_York"); 514 TimeZone bogusTimeZone = new SimpleTimeZone(1234, "Etc/Unknown"); 515 Calendar calendar = Calendar.getInstance(); 516 ParsePosition parsePosition = new ParsePosition(0); 517 518 ULocale[] locales = ULocale.getAvailableLocales(); 519 int count = 0; 520 for (int i = 0; i < locales.length; ++i) { 521 // skip the country locales unless we are doing exhaustive tests 522 if (getInclusion() < 6) { 523 if (locales[i].getCountry().length() > 0) { 524 continue; 525 } 526 } 527 count++; 528 // Skipping some test case in the non-exhaustive mode to reduce the test time 529 //ticket#6503 530 if(params.inclusion<=5 && count%3!=0){ 531 continue; 532 } 533 logln(locales[i].toString()); 534 DateTimePatternGenerator dtpgen 535 = DateTimePatternGenerator.getInstance(locales[i]); 536 537 for (int style1 = DateFormat.FULL; style1 <= DateFormat.SHORT; ++style1) { 538 final SimpleDateFormat oldFormat = (SimpleDateFormat) DateFormat.getTimeInstance(style1, locales[i]); 539 String pattern = oldFormat.toPattern(); 540 String newPattern = dtpgen.replaceFieldTypes(pattern, "VVVV"); // replaceZoneString(pattern, "VVVV"); 541 if (newPattern.equals(pattern)) { 542 continue; 543 } 544 // verify that it roundtrips parsing 545 SimpleDateFormat newFormat = new SimpleDateFormat(newPattern, locales[i]); 546 newFormat.setTimeZone(testTimeZone); 547 String formatted = newFormat.format(testDate); 548 calendar.setTimeZone(bogusTimeZone); 549 parsePosition.setIndex(0); 550 newFormat.parse(formatted, calendar, parsePosition); 551 if (parsePosition.getErrorIndex() >= 0) { 552 errln("Failed parse with VVVV:\t" + locales[i] + ",\t\"" + pattern + "\",\t\"" + newPattern + "\",\t\"" + formatted.substring(0,parsePosition.getErrorIndex()) + "{}" + formatted.substring(parsePosition.getErrorIndex()) + "\""); 553 } else if (!calendar.getTimeZone().getID().equals(testTimeZone.getID())) { 554 errln("Failed timezone roundtrip with VVVV:\t" + locales[i] + ",\t\"" + pattern + "\",\t\"" + newPattern + "\",\t\"" + formatted + "\",\t" + calendar.getTimeZone().getID() + " != " + testTimeZone.getID()); 555 } else { 556 logln(locales[i] + ":\t\"" + pattern + "\" => \t\"" + newPattern + "\"\t" + formatted); 557 } 558 } 559 } 560 } 561 TestVariableCharacters()562 public void TestVariableCharacters() { 563 UnicodeSet valid = new UnicodeSet("[G y Y u U r Q q M L l w W d D F g E e c a h H K k m s S A z Z O v V X x]"); 564 for (char c = 0; c < 0xFF; ++c) { 565 boolean works = false; 566 try { 567 VariableField vf = new VariableField(String.valueOf(c), true); 568 logln("VariableField " + vf.toString()); 569 works = true; 570 } catch (Exception e) {} 571 if (works != valid.contains(c)) { 572 if (works) { 573 errln("VariableField can be created with illegal character: " + c); 574 } else { 575 errln("VariableField can't be created with legal character: " + c); 576 } 577 } 578 } 579 } 580 581 static String[] DATE_STYLE_NAMES = { 582 "FULL", "LONG", "MEDIUM", "SHORT" 583 }; 584 585 /** 586 * @param fullOrder 587 * @param longOrder 588 */ checkCompatible(int style1, int style2, ULocale uLocale)589 private void checkCompatible(int style1, int style2, ULocale uLocale) { 590 DateOrder order1 = getOrdering(style1, uLocale); 591 DateOrder order2 = getOrdering(style2, uLocale); 592 if (!order1.hasSameOrderAs(order2)) { 593 // Note: This test case was updated by #6806 and no longer reports 594 // ordering difference as an error case. 595 logln(showOrderComparison(uLocale, style1, style2, order1, order2)); 596 } 597 } 598 showOrderComparison(ULocale uLocale, int style1, int style2, DateOrder order1, DateOrder order2)599 private String showOrderComparison(ULocale uLocale, int style1, int style2, DateOrder order1, DateOrder order2) { 600 String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(style1, uLocale)).toPattern(); 601 String pattern2 = ((SimpleDateFormat) DateFormat.getDateInstance(style2, uLocale)).toPattern(); 602 return "Mismatch in in ordering for " + uLocale + ": " + DATE_STYLE_NAMES[style1] + ": " + order1 + ", <" + pattern1 603 + ">; " 604 + DATE_STYLE_NAMES[style2] + ": " + order2 + ", <" + pattern2 + ">; " ; 605 } 606 607 /** 608 * Main date fields -- Poor-man's enum -- change to real enum when we get JDK 1.5 609 */ 610 public static class DateFieldType { 611 private String name; DateFieldType(String string)612 private DateFieldType(String string) { 613 name = string; 614 } 615 616 public static DateFieldType 617 YEAR = new DateFieldType("YEAR"), 618 MONTH = new DateFieldType("MONTH"), 619 DAY = new DateFieldType("DAY"); 620 toString()621 public String toString() { 622 return name; 623 } 624 } 625 626 /** 627 * Simple struct for output from getOrdering 628 */ 629 static class DateOrder { 630 int monthLength; 631 DateFieldType[] fields = new DateFieldType[3]; 632 isCompatible(DateOrder other)633 public boolean isCompatible(DateOrder other) { 634 return monthLength == other.monthLength; 635 } 636 /** 637 * @param order2 638 * @return 639 */ hasSameOrderAs(DateOrder other)640 public boolean hasSameOrderAs(DateOrder other) { 641 // TODO Auto-generated method stub 642 return fields[0] == other.fields[0] && fields[1] == other.fields[1] && fields[2] == other.fields[2]; 643 } toString()644 public String toString() { 645 return "{" + monthLength + ", " + fields[0] + ", " + fields[1] + ", " + fields[2] + "}"; 646 } equals(Object that)647 public boolean equals(Object that) { 648 DateOrder other = (DateOrder) that; 649 return monthLength == other.monthLength && fields[0] == other.fields[0] && fields[1] == other.fields[1] && fields[2] == other.fields[2]; 650 } 651 } 652 653 DateTimePatternGenerator.FormatParser formatParser = new DateTimePatternGenerator.FormatParser (); 654 DateTimePatternGenerator generator = DateTimePatternGenerator.getEmptyInstance(); 655 656 private Calendar sampleCalendar; 657 { 658 sampleCalendar = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles")); 659 sampleCalendar.set(1999, Calendar.OCTOBER, 13, 23, 58, 59); 660 } 661 662 private Date sampleDate = sampleCalendar.getTime(); 663 private TimeZone gmt = TimeZone.getTimeZone("Etc/GMT"); 664 665 /** 666 * Replace the zone string with a different type, eg v's for z's, etc. <p>Called with a pattern, such as one gotten from 667 * <pre> 668 * String pattern = ((SimpleDateFormat) DateFormat.getTimeInstance(style, locale)).toPattern(); 669 * </pre> 670 * @param pattern original pattern to change, such as "HH:mm zzzz" 671 * @param newZone Must be: z, zzzz, Z, ZZZZ, v, vvvv, V, or VVVV 672 * @return 673 */ replaceZoneString(String pattern, String newZone)674 public String replaceZoneString(String pattern, String newZone) { 675 final List itemList = formatParser.set(pattern).getItems(); 676 boolean changed = false; 677 for (int i = 0; i < itemList.size(); ++i) { 678 Object item = itemList.get(i); 679 if (item instanceof VariableField) { 680 VariableField variableField = (VariableField) item; 681 if (variableField.getType() == DateTimePatternGenerator.ZONE) { 682 if (!variableField.toString().equals(newZone)) { 683 changed = true; 684 itemList.set(i, new VariableField(newZone, true)); 685 } 686 } 687 } 688 } 689 return changed ? formatParser.toString() : pattern; 690 } 691 containsZone(String pattern)692 public boolean containsZone(String pattern) { 693 for (Iterator it = formatParser.set(pattern).getItems().iterator(); it.hasNext();) { 694 Object item = it.next(); 695 if (item instanceof VariableField) { 696 VariableField variableField = (VariableField) item; 697 if (variableField.getType() == DateTimePatternGenerator.ZONE) { 698 return true; 699 } 700 } 701 } 702 return false; 703 } 704 705 /** 706 * Get the ordering from a particular date format. Best is to use 707 * DateFormat.FULL to get the format with String form month (like "January") 708 * and DateFormat.SHORT for the numeric format order. They may be different. 709 * (Theoretically all 4 formats could be different but that never happens in 710 * practice.) 711 * 712 * @param style 713 * DateFormat.FULL..DateFormat.SHORT 714 * @param locale 715 * desired locale. 716 * @return 717 * @return list of ordered items DateFieldType (I 718 * didn't know what form you really wanted so this is just a 719 * stand-in.) 720 */ getOrdering(int style, ULocale locale)721 private DateOrder getOrdering(int style, ULocale locale) { 722 // and the date pattern 723 String pattern = ((SimpleDateFormat) DateFormat.getDateInstance(style, locale)).toPattern(); 724 int count = 0; 725 DateOrder result = new DateOrder(); 726 727 for (Iterator it = formatParser.set(pattern).getItems().iterator(); it.hasNext();) { 728 Object item = it.next(); 729 if (!(item instanceof String)) { 730 // the first character of the variable field determines the type, 731 // according to CLDR. 732 String variableField = item.toString(); 733 switch (variableField.charAt(0)) { 734 case 'y': case 'Y': case 'u': 735 result.fields[count++] = DateFieldType.YEAR; 736 break; 737 case 'M': case 'L': 738 result.monthLength = variableField.length(); 739 if (result.monthLength < 2) { 740 result.monthLength = 2; 741 } 742 result.fields[count++] = DateFieldType.MONTH; 743 break; 744 case 'd': case 'D': case 'F': case 'g': 745 result.fields[count++] = DateFieldType.DAY; 746 break; 747 } 748 } 749 } 750 return result; 751 } 752 /* Tests the method 753 * public static DateTimePatternGenerator getInstance() 754 */ TestGetInstance()755 public void TestGetInstance(){ 756 try{ 757 DateTimePatternGenerator.getInstance(); 758 } catch(Exception e){ 759 errln("DateTimePatternGenerator.getInstance() was not suppose to " + 760 "return an exception."); 761 } 762 } 763 764 /* Tests the method 765 * public String getSkeleton(String pattern) 766 */ TestGetSkeleton()767 public void TestGetSkeleton(){ 768 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 769 String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd"}; 770 String[] results = {"MMDD","MMMDD","MMMDD","MMMDD","Mdd","MMMMd"}; 771 for(int i=0; i<cases.length; i++){ 772 if(!dtpg.getSkeleton(cases[i]).equals(results[i])){ 773 errln("DateTimePatternGenerator.getSkeleton(String) did " + 774 "return the expected result when passing " + cases[i] + 775 " and expected " + results[i] + " but got " + 776 dtpg.getSkeleton(cases[i])); 777 } 778 } 779 } 780 781 /* Tests the method 782 * public String getBaseSkeleton(String pattern) 783 */ TestGetBaseSkeleton()784 public void TestGetBaseSkeleton(){ 785 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 786 String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd"}; 787 String[] results = {"MD","MMMD","MMMD","MMMD","Md","MMMMd"}; 788 for(int i=0; i<cases.length; i++){ 789 if(!dtpg.getBaseSkeleton(cases[i]).equals(results[i])){ 790 errln("DateTimePatternGenerator.getSkeleton(String) did " + 791 "return the expected result when passing " + cases[i] + 792 " and expected " + results[i] + " but got " + 793 dtpg.getBaseSkeleton(cases[i])); 794 } 795 } 796 } 797 798 /* Tests the method 799 * public Map<String, String> getSkeletons(Map<String, String> result) 800 */ TestGetSkeletons()801 public void TestGetSkeletons(){ 802 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 803 // Tests when "if (result == null)" is true 804 try{ 805 dtpg.getSkeletons(null); 806 } catch(Exception e){ 807 errln("DateTimePatternGenerator.getSkeletons(Map) was suppose to " + 808 "return a new LinkedHashMap for a null parameter."); 809 } 810 811 // Tests when "if (result == null)" is false 812 Map<String,String> mm = new LinkedHashMap<String, String>(); 813 try{ 814 dtpg.getSkeletons(mm); 815 } catch(Exception e){ 816 errln("DateTimePatternGenerator.getSkeletons(Map) was suppose to " + 817 "return a new LinkedHashMap for a LinkedHashMap parameter."); 818 } 819 } 820 821 /* Tests the method 822 * public Set<String> getBaseSkeletons(Set<String> result) 823 */ TestGetBaseSkeletons()824 public void TestGetBaseSkeletons(){ 825 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 826 // Tests when "if (result == null)" is true 827 try{ 828 dtpg.getBaseSkeletons(null); 829 } catch(Exception e){ 830 errln("DateTimePatternGenerator.getBaseSkeletons(Map) was suppose to " + 831 "return a new LinkedHashMap for a null parameter."); 832 } 833 834 // Tests when "if (result == null)" is false 835 Set<String> mm = new HashSet<String>(); 836 try{ 837 dtpg.getBaseSkeletons(mm); 838 } catch(Exception e){ 839 errln("DateTimePatternGenerator.getBaseSkeletons(Map) was suppose to " + 840 "return a new LinkedHashMap for a HashSet parameter."); 841 } 842 } 843 844 /* Tests the method 845 * public String getDecimal() 846 */ TestGetDecimal()847 public void TestGetDecimal(){ 848 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 849 if(!dtpg.getDecimal().equals(".")){ 850 errln("DateTimePatternGenerator.getDecimal() was to return '.' " + 851 "when the object gets a new instance."); 852 } 853 854 String[] cases = {",","-","","*","&","a","0"}; 855 for(int i=0; i<cases.length; i++){ 856 dtpg.setDecimal(cases[i]); 857 if(!dtpg.getDecimal().equals(cases[i])){ 858 errln("DateTimePatternGenerator.getDecimal() was to return " + cases[i] + 859 "when setting decimal with " + cases[i]); 860 } 861 } 862 } 863 864 /* Tests the method 865 * public Collection<String> getRedundants(Collection<String> output) 866 */ TestGetRedundants()867 public void TestGetRedundants(){ 868 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 869 870 // Tests when "if (output == null)" is true 871 try{ 872 dtpg.getRedundants(null); 873 } catch(Exception e){ 874 errln("DateTimeGenerator.getRedundants was not suppose to return " + 875 "an exception when passing a null parameter."); 876 } 877 878 // Tests when "if (output == null)" is false 879 try{ 880 Collection<String> out = new LinkedHashSet<String>(); 881 dtpg.getRedundants(out); 882 } catch(Exception e){ 883 errln("DateTimeGenerator.getRedundants was not suppose to return " + 884 "an exception when passing a new LinkedHashSet<String>() parameter."); 885 } 886 887 } 888 889 /* Tests the method 890 * public String getAppendItemFormat(int field) 891 */ TestGetAppendItemFormat()892 public void TestGetAppendItemFormat(){ 893 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 894 String[] cases = {"d","u","m","m","y"}; 895 for(int i=0; i<cases.length; i++){ 896 dtpg.setAppendItemFormat(i, cases[i]); 897 if(!dtpg.getAppendItemFormat(i).equals(cases[i])){ 898 errln("DateTimePatternGeneratorgetAppendItemFormat(int field) " + 899 "did not return as expected. Value set at " + i + " was " + 900 cases[i] + " but got back " + dtpg.getAppendItemFormat(i)); 901 } 902 } 903 } 904 905 /* Tests the method 906 * public String getAppendItemName(int field) 907 */ 908 private final class AppendItemName { 909 public int field; 910 public String name; AppendItemName(int f, String n)911 public AppendItemName(int f, String n) { 912 field = f; 913 name = n; 914 } 915 } 916 TestGetAppendItemName()917 public void TestGetAppendItemName(){ 918 final AppendItemName[] appendItemNames = { 919 new AppendItemName( DateTimePatternGenerator.YEAR, "vuosi" ), 920 new AppendItemName( DateTimePatternGenerator.MONTH, "kuukausi" ), 921 new AppendItemName( DateTimePatternGenerator.WEEKDAY, "viikonp\u00E4iv\u00E4" ), 922 new AppendItemName( DateTimePatternGenerator.DAY, "p\u00E4iv\u00E4" ), 923 new AppendItemName( DateTimePatternGenerator.HOUR, "tunti" ), 924 }; 925 926 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 927 String[] cases = {"d","u","m","m","y"}; 928 for(int i=0; i<cases.length; i++){ 929 dtpg.setAppendItemName(i, cases[i]); 930 if(!dtpg.getAppendItemName(i).equals(cases[i])){ 931 errln("DateTimePatternGenerator.getAppendItemFormat(int field) " + 932 "did not return as expected. Value set at " + i + " was " + 933 cases[i] + " but got back " + dtpg.getAppendItemName(i)); 934 } 935 } 936 937 DateTimePatternGenerator dtpgfi = DateTimePatternGenerator.getInstance(ULocale.forLanguageTag("fi")); 938 for (AppendItemName appendItemName: appendItemNames) { 939 String name = dtpgfi.getAppendItemName(appendItemName.field); 940 if (!name.equals(appendItemName.name)) { 941 errln("DateTimePatternGenerator.getAppendItemName returns invalid name for field " + appendItemName.field); 942 } 943 } 944 } 945 946 /* Tests the method 947 * public static boolean isSingleField(String skeleton) 948 */ 949 @SuppressWarnings("static-access") TestIsSingleField()950 public void TestIsSingleField(){ 951 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 952 String[] cases = {" ", "m","mm","md","mmd","mmdd"}; 953 boolean[] results = {true,true,true,false,false,false}; 954 for(int i=0; i<cases.length; i++){ 955 if(dtpg.isSingleField(cases[i]) != results[i]){ 956 errln("DateTimePatternGenerator.isSingleField(String skeleton) " + 957 "did not return as expected. Value passed was " + cases[i] + 958 " but got back " + dtpg.isSingleField(cases[i])); 959 } 960 } 961 } 962 963 /* Tests the method 964 * public Object freeze() 965 * public Object cloneAsThawed() 966 */ TestFreezeAndCloneAsThawed()967 public void TestFreezeAndCloneAsThawed(){ 968 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 969 970 if(dtpg.isFrozen() != false){ 971 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " + 972 "for a DateTimePatternGenerator object that was just " + 973 "created."); 974 } 975 976 dtpg.freeze(); 977 if(dtpg.isFrozen() != true){ 978 errln("DateTimePatternGenerator.isFrozen() is suppose to return true " + 979 "for a DateTimePatternGenerator object that was just " + 980 "created and freeze."); 981 } 982 983 DateTimePatternGenerator dtpg2 = (DateTimePatternGenerator) dtpg.cloneAsThawed(); 984 if(dtpg.isFrozen() != false){ 985 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " + 986 "for a DateTimePatternGenerator object that was just " + 987 "clone as thawed."); 988 } 989 if(dtpg2.isFrozen() != false){ 990 errln("DateTimePatternGenerator.isFrozen() is suppose to return false " + 991 "for a second DateTimePatternGenerator object that was just " + 992 "clone as thawed."); 993 } 994 } 995 996 /* Tests the method 997 * public Object clone() 998 */ TestClone()999 public void TestClone(){ 1000 DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(); 1001 DateTimePatternGenerator dtpg2 = (DateTimePatternGenerator) dtpg.clone(); 1002 dtpg = (DateTimePatternGenerator) dtpg2.clone(); 1003 } 1004 1005 /* Tests the constructor 1006 * public VariableField(String string) 1007 */ 1008 @SuppressWarnings("unused") TestVariableField_String()1009 public void TestVariableField_String(){ 1010 String[] cases = {"d","mm","aa"}; 1011 String[] invalid = {null,"","dummy"}; 1012 for(int i=0; i<cases.length; i++){ 1013 try{ 1014 VariableField vf = new VariableField(cases[i]); 1015 } catch(Exception e){ 1016 errln("VariableField constructor was not suppose to return " + 1017 "an exception when created when passing " + cases[i]); 1018 } 1019 } 1020 for(int i=0; i<invalid.length; i++){ 1021 try{ 1022 VariableField vf = new VariableField(invalid[i]); 1023 errln("VariableField constructor was suppose to return " + 1024 "an exception when created when passing " + invalid[i]); 1025 } catch(Exception e){} 1026 } 1027 } 1028 1029 /* Tests the method 1030 * public FormatParser set(String string, boolean strict) 1031 */ TestSet()1032 public void TestSet(){ 1033 FormatParser fp = new FormatParser(); 1034 //Tests when "if (string.length() == 0)" is true 1035 try{ 1036 fp.set("",true); 1037 }catch(Exception e){ 1038 errln("FormatParser.set(String,boolean) was not suppose to " + 1039 "return an exception."); 1040 } 1041 } 1042 1043 /* Tests the method 1044 * public String toString() 1045 */ TestToString()1046 public void TestToString(){ 1047 FormatParser fp = new FormatParser(); 1048 if(!fp.toString().equals("")){ 1049 errln("FormatParser.toString() was suppose to return an " + 1050 "empty string for a new FormatParser object."); 1051 } 1052 1053 String[] cases = {"m","d","y","mm","mmm","mm dd","mm':'dd","mm-dd-yyyy"}; 1054 String[] results = {"m","d","y","mm","mmm","mm dd","mm:dd","mm-dd-yyyy"}; 1055 for(int i=0; i<cases.length; i++){ 1056 fp.set(cases[i]); 1057 if(!fp.toString().equals(results[i])){ 1058 errln("FormatParser.toString() was suppose to return " + results[i] + 1059 " after setting the object. Got: " + fp.toString()); 1060 } 1061 } 1062 } 1063 1064 /* Tests the method 1065 * public boolean hasDateAndTimeFields() 1066 */ TestHasDateAndTimeFields()1067 public void TestHasDateAndTimeFields(){ 1068 FormatParser fp = new FormatParser(); 1069 if(fp.hasDateAndTimeFields() != false){ 1070 errln("FormatParser.hasDateAndTimeFields() was suppose to return " + 1071 "false when a new object is created."); 1072 } 1073 1074 String[] cases = {"MMDDYY", "HHMMSS", "", "MM/DD/YYYY HH:MM:SS", 1075 "MMDDYY HHMMSS", "HHMMSS MMDDYYYY", "HMS MDY"}; 1076 boolean[] results = {false,true,false,true,true,true,true}; 1077 for(int i=0; i<cases.length; i++){ 1078 fp.set(cases[i]); 1079 if(fp.hasDateAndTimeFields() != results[i]){ 1080 errln("FormatParser.hasDateAndTimeFields() was suppose to " + 1081 "return " + results[i] + " but returned " + 1082 fp.hasDateAndTimeFields() + " for parameter " + 1083 cases[i] + " that is set to FormatParser."); 1084 } 1085 } 1086 } 1087 1088 /* Tests the method 1089 * private void checkFrozen() 1090 * from public void setDateTimeFormat(String dateTimeFormat) 1091 */ TestCheckFrozen()1092 public void TestCheckFrozen(){ 1093 // Tests when "if (isFrozen())" is true 1094 DateTimePatternGenerator dt = DateTimePatternGenerator.getInstance(); 1095 try{ 1096 dt.freeze(); 1097 dt.setDateTimeFormat("MMDDYYYY"); 1098 errln("DateTimePatternGenerator.checkFrozen() was suppose to " + 1099 "return an exception when trying to setDateTimeFormat " + 1100 "for a frozen object."); 1101 } catch(Exception e){} 1102 dt = (DateTimePatternGenerator) dt.cloneAsThawed(); 1103 } 1104 1105 /* Tests the method 1106 * public String getFields(String pattern) 1107 */ TestGetFields()1108 public void TestGetFields(){ 1109 DateTimePatternGenerator dt = DateTimePatternGenerator.getInstance(); 1110 String[] cases = {"MMDDYY", "HHMMSS", "", "MM/DD/YYYY HH:MM:SS", 1111 "MMDDYY HHMMSS", "HHMMSS MMDDYYYY", "HMS MDY"}; 1112 String[] results = {"{Month:N}{Day_Of_Year:N}{Year:N}", 1113 "{Hour:N}{Month:N}{Fractional_Second:N}","", 1114 "{Month:N}/{Day_Of_Year:N}/{Year:N} {Hour:N}:{Month:N}:{Fractional_Second:N}", 1115 "{Month:N}{Day_Of_Year:N}{Year:N} {Hour:N}{Month:N}{Fractional_Second:N}", 1116 "{Hour:N}{Month:N}{Fractional_Second:N} {Month:N}{Day_Of_Year:N}{Year:N}", 1117 "{Hour:N}{Month:N}{Fractional_Second:N} {Month:N}{Day_Of_Year:N}{Year:N}"}; 1118 for(int i=0; i<cases.length; i++){ 1119 if(!dt.getFields(cases[i]).equals(results[i])) { 1120 errln("DateTimePatternGenerator.getFields(String) did not " + 1121 "not return an expected result when passing " + cases[i] + 1122 ". Got " + dt.getFields(cases[i]) + " but expected " + 1123 results[i]); 1124 } 1125 } 1126 } 1127 1128 /* 1129 * Test case for DateFormatPatternGenerator threading problem #7169 1130 */ TestT7169()1131 public void TestT7169() { 1132 Thread[] workers = new Thread[10]; 1133 for (int i = 0 ; i < workers.length; i++) { 1134 workers[i] = new Thread(new Runnable() { 1135 public void run() { 1136 try { 1137 for (int i = 0; i < 50; i++) { 1138 DateTimePatternGenerator patternGenerator = 1139 DateTimePatternGenerator.getFrozenInstance(ULocale.US); 1140 patternGenerator.getBestPattern("MMMMd"); 1141 } 1142 } catch (Exception e) { 1143 errln("FAIL: Caught an exception (frozen)" + e); 1144 } 1145 try { 1146 for (int i = 0; i < 50; i++) { 1147 DateTimePatternGenerator patternGenerator = 1148 DateTimePatternGenerator.getInstance(ULocale.US); 1149 patternGenerator.getBestPattern("MMMMd"); 1150 } 1151 } catch (Exception e) { 1152 errln("FAIL: Caught an exception " + e); 1153 } 1154 } 1155 }); 1156 } 1157 for (Thread wk : workers) { 1158 wk.start(); 1159 } 1160 for (Thread wk : workers) { 1161 try { 1162 wk.join(); 1163 } catch (InterruptedException ie) { 1164 1165 } 1166 } 1167 } 1168 1169 /** 1170 * Test handling of options 1171 * 1172 * For reference, as of ICU 4.3.3, 1173 * root/gregorian has 1174 * Hm{"H:mm"} 1175 * Hms{"H:mm:ss"} 1176 * hm{"h:mm a"} 1177 * hms{"h:mm:ss a"} 1178 * en/gregorian has 1179 * Hm{"H:mm"} 1180 * Hms{"H:mm:ss"} 1181 * hm{"h:mm a"} 1182 * be/gregorian has 1183 * HHmmss{"HH.mm.ss"} 1184 * Hm{"HH.mm"} 1185 * hm{"h.mm a"} 1186 * hms{"h.mm.ss a"} 1187 */ 1188 private final class TestOptionsItem { 1189 public String locale; 1190 public String skeleton; 1191 public String expectedPattern; 1192 public int options; 1193 // Simple constructor TestOptionsItem(String loc, String skel, String expectedPat, int opts)1194 public TestOptionsItem(String loc, String skel, String expectedPat, int opts) { 1195 locale = loc; 1196 skeleton = skel; 1197 expectedPattern = expectedPat; 1198 options = opts; 1199 } 1200 } TestOptions()1201 public void TestOptions() { 1202 final TestOptionsItem[] testOptionsData = { 1203 new TestOptionsItem( "en", "Hmm", "HH:mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1204 new TestOptionsItem( "en", "HHmm", "HH:mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1205 new TestOptionsItem( "en", "hhmm", "h:mm a", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1206 new TestOptionsItem( "en", "Hmm", "HH:mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1207 new TestOptionsItem( "en", "HHmm", "HH:mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1208 new TestOptionsItem( "en", "hhmm", "hh:mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1209 new TestOptionsItem( "be", "Hmm", "HH.mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1210 new TestOptionsItem( "be", "HHmm", "HH.mm", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1211 new TestOptionsItem( "be", "hhmm", "h.mm a", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1212 new TestOptionsItem( "be", "Hmm", "H.mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1213 new TestOptionsItem( "be", "HHmm", "HH.mm", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1214 new TestOptionsItem( "be", "hhmm", "hh.mm a", DateTimePatternGenerator.MATCH_HOUR_FIELD_LENGTH ), 1215 // 1216 new TestOptionsItem( "en", "yyyy", "yyyy", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1217 new TestOptionsItem( "en", "YYYY", "YYYY", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1218 new TestOptionsItem( "en", "U", "y", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1219 new TestOptionsItem( "en@calendar=japanese", "yyyy", "y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1220 new TestOptionsItem( "en@calendar=japanese", "YYYY", "Y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1221 new TestOptionsItem( "en@calendar=japanese", "U", "y G", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1222 new TestOptionsItem( "en@calendar=chinese", "yyyy", "r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1223 new TestOptionsItem( "en@calendar=chinese", "YYYY", "Y(Y)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), // not a good result, want r(Y) or r(U) 1224 new TestOptionsItem( "en@calendar=chinese", "U", "r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1225 new TestOptionsItem( "en@calendar=chinese", "Gy", "r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1226 new TestOptionsItem( "en@calendar=chinese", "GU", "r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1227 new TestOptionsItem( "en@calendar=chinese", "ULLL", "MMM U", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1228 new TestOptionsItem( "en@calendar=chinese", "yMMM", "MMM r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1229 new TestOptionsItem( "en@calendar=chinese", "GUMMM", "MMM r(U)", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1230 new TestOptionsItem( "zh@calendar=chinese", "yyyy", "rU\u5E74", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1231 new TestOptionsItem( "zh@calendar=chinese", "YYYY", "YY\u5E74", DateTimePatternGenerator.MATCH_NO_OPTIONS ), // not a good result, want r(Y) or r(U) 1232 new TestOptionsItem( "zh@calendar=chinese", "U", "rU\u5E74", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1233 new TestOptionsItem( "zh@calendar=chinese", "Gy", "rU\u5E74", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1234 new TestOptionsItem( "zh@calendar=chinese", "GU", "rU\u5E74", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1235 new TestOptionsItem( "zh@calendar=chinese", "ULLL", "U\u5E74MMM", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1236 new TestOptionsItem( "zh@calendar=chinese", "yMMM", "rU\u5E74MMM", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1237 new TestOptionsItem( "zh@calendar=chinese", "GUMMM", "rU\u5E74MMM", DateTimePatternGenerator.MATCH_NO_OPTIONS ), 1238 }; 1239 1240 for (int i = 0; i < testOptionsData.length; ++i) { 1241 ULocale uloc = new ULocale(testOptionsData[i].locale); 1242 DateTimePatternGenerator dtpgen = DateTimePatternGenerator.getInstance(uloc); 1243 String pattern = dtpgen.getBestPattern(testOptionsData[i].skeleton, testOptionsData[i].options); 1244 if (pattern.compareTo(testOptionsData[i].expectedPattern) != 0) { 1245 errln("Locale " + testOptionsData[i].locale + ", skeleton " + testOptionsData[i].skeleton + 1246 ", options " + ((testOptionsData[i].options != 0)? "!=0": "==0") + 1247 ", expected pattern " + testOptionsData[i].expectedPattern + ", got " + pattern); 1248 } 1249 } 1250 } 1251 1252 /** 1253 * Test that DTPG can handle all valid pattern character / length combinations 1254 */ 1255 private final class AllFieldsTestItem { 1256 public char patternChar; 1257 public int[] fieldLengths; 1258 public String mustIncludeOneOf; 1259 // Simple constructor AllFieldsTestItem(char pC, int[] fL, String mI)1260 public AllFieldsTestItem(char pC, int[] fL, String mI) { 1261 patternChar = pC; 1262 fieldLengths = fL; 1263 mustIncludeOneOf = mI; 1264 } 1265 } TestAllFieldPatterns()1266 public void TestAllFieldPatterns() { 1267 String[] localeNames = { 1268 "root", 1269 "root@calendar=japanese", 1270 "root@calendar=chinese", 1271 "en", 1272 "en@calendar=japanese", 1273 "en@calendar=chinese", 1274 }; 1275 final AllFieldsTestItem[] testItems = { 1276 // pat fieldLengths generated pattern must 1277 // chr to test include one of these 1278 new AllFieldsTestItem( 'G', new int[]{1,2,3,4,5}, "G" ), // era 1279 // year 1280 new AllFieldsTestItem( 'y', new int[]{1,2,3,4}, "yU" ), // year 1281 new AllFieldsTestItem( 'Y', new int[]{1,2,3,4}, "Y" ), // year for week of year 1282 new AllFieldsTestItem( 'u', new int[]{1,2,3,4,5}, "yuU" ), // extended year 1283 new AllFieldsTestItem( 'U', new int[]{1,2,3,4,5}, "yU" ), // cyclic year name 1284 // quarter 1285 new AllFieldsTestItem( 'Q', new int[]{1,2,3,4}, "Qq" ), // x 1286 new AllFieldsTestItem( 'q', new int[]{1,2,3,4}, "Qq" ), // standalone 1287 // month 1288 new AllFieldsTestItem( 'M', new int[]{1,2,3,4,5}, "ML" ), // x 1289 new AllFieldsTestItem( 'L', new int[]{1,2,3,4,5}, "ML" ), // standalone 1290 // week 1291 new AllFieldsTestItem( 'w', new int[]{1,2}, "w" ), // week of year 1292 new AllFieldsTestItem( 'W', new int[]{1}, "W" ), // week of month 1293 // day 1294 new AllFieldsTestItem( 'd', new int[]{1,2}, "d" ), // day of month 1295 new AllFieldsTestItem( 'D', new int[]{1,2,3}, "D" ), // day of year 1296 new AllFieldsTestItem( 'F', new int[]{1}, "F" ), // day of week in month 1297 new AllFieldsTestItem( 'g', new int[]{7}, "g" ), // modified julian day 1298 // weekday 1299 new AllFieldsTestItem( 'E', new int[]{1,2,3,4,5,6}, "Eec" ), // day of week 1300 new AllFieldsTestItem( 'e', new int[]{1,2,3,4,5,6}, "Eec" ), // local day of week 1301 new AllFieldsTestItem( 'c', new int[]{1,2,3,4,5,6}, "Eec" ), // standalone local day of week 1302 // day period 1303 // new AllFieldsTestItem( 'a', new int[]{1}, "a" ), // am or pm // not clear this one is supposed to work (it doesn't) 1304 // hour 1305 new AllFieldsTestItem( 'h', new int[]{1,2}, "hK" ), // 12 (1-12) 1306 new AllFieldsTestItem( 'H', new int[]{1,2}, "Hk" ), // 24 (0-23) 1307 new AllFieldsTestItem( 'K', new int[]{1,2}, "hK" ), // 12 (0-11) 1308 new AllFieldsTestItem( 'k', new int[]{1,2}, "Hk" ), // 24 (1-24) 1309 new AllFieldsTestItem( 'j', new int[]{1,2}, "hHKk" ), // locale default 1310 // minute 1311 new AllFieldsTestItem( 'm', new int[]{1,2}, "m" ), // x 1312 // second & fractions 1313 new AllFieldsTestItem( 's', new int[]{1,2}, "s" ), // x 1314 new AllFieldsTestItem( 'S', new int[]{1,2,3,4}, "S" ), // fractional second 1315 new AllFieldsTestItem( 'A', new int[]{8}, "A" ), // milliseconds in day 1316 // zone 1317 new AllFieldsTestItem( 'z', new int[]{1,2,3,4}, "z" ), // x 1318 new AllFieldsTestItem( 'Z', new int[]{1,2,3,4,5}, "Z" ), // x 1319 new AllFieldsTestItem( 'O', new int[]{1,4}, "O" ), // x 1320 new AllFieldsTestItem( 'v', new int[]{1,4}, "v" ), // x 1321 new AllFieldsTestItem( 'V', new int[]{1,2,3,4}, "V" ), // x 1322 new AllFieldsTestItem( 'X', new int[]{1,2,3,4,5}, "X" ), // x 1323 new AllFieldsTestItem( 'x', new int[]{1,2,3,4,5}, "x" ), // x 1324 }; 1325 final int FIELD_LENGTH_MAX = 8; 1326 1327 for (String localeName: localeNames) { 1328 ULocale uloc = new ULocale(localeName); 1329 DateTimePatternGenerator dtpgen = DateTimePatternGenerator.getInstance(uloc); 1330 for (AllFieldsTestItem testItem: testItems) { 1331 char[] skelBuf = new char[FIELD_LENGTH_MAX]; 1332 for (int chrIndx = 0; chrIndx < FIELD_LENGTH_MAX; chrIndx++) { 1333 skelBuf[chrIndx] = testItem.patternChar; 1334 } 1335 for (int lenIndx = 0; lenIndx < testItem.fieldLengths.length; lenIndx++) { 1336 int skelLen = testItem.fieldLengths[lenIndx]; 1337 if (skelLen > FIELD_LENGTH_MAX) { 1338 continue; 1339 }; 1340 String skeleton = new String(skelBuf, 0, skelLen); 1341 String pattern = dtpgen.getBestPattern(skeleton); 1342 if (pattern.length() <= 0) { 1343 errln("DateTimePatternGenerator getBestPattern for locale " + localeName + 1344 ", skeleton " + skeleton + ", produces 0-length pattern"); 1345 } else { 1346 // test that resulting pattern has at least one char in mustIncludeOneOf 1347 boolean inQuoted = false; 1348 int patIndx, patLen = pattern.length(); 1349 for (patIndx = 0; patIndx < patLen; patIndx++) { 1350 char c = pattern.charAt(patIndx); 1351 if (c == '\'') { 1352 inQuoted = !inQuoted; 1353 } else if (!inQuoted && c <= 'z' && c >= 'A') { 1354 if (testItem.mustIncludeOneOf.indexOf(c) >= 0) { 1355 break; 1356 } 1357 } 1358 } 1359 if (patIndx >= patLen) { 1360 errln("DateTimePatternGenerator getBestPattern for locale " + localeName + 1361 ", skeleton " + skeleton + 1362 ", produces pattern without required chars: " + pattern); 1363 } 1364 } 1365 } 1366 } 1367 } 1368 } 1369 TestJavaLocale()1370 public void TestJavaLocale() { 1371 DateTimePatternGenerator genUloc = DateTimePatternGenerator.getInstance(ULocale.GERMANY); 1372 DateTimePatternGenerator genLoc = DateTimePatternGenerator.getInstance(Locale.GERMANY); 1373 1374 final String pat = "yMdHms"; 1375 String patUloc = genUloc.getBestPattern(pat); 1376 String patLoc = genLoc.getBestPattern(pat); 1377 1378 assertEquals("German pattern 'yMdHms' - getInstance with Java Locale", patUloc, patLoc); 1379 } 1380 } 1381