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