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