1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 2008-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 
9 #include "unicode/utypes.h"
10 
11 #if !UCONFIG_NO_FORMATTING
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "dtptngts.h"
16 
17 #include "unicode/calendar.h"
18 #include "unicode/smpdtfmt.h"
19 #include "unicode/dtfmtsym.h"
20 #include "unicode/dtptngen.h"
21 #include "cmemory.h"
22 #include "loctest.h"
23 
24 
25 // This is an API test, not a unit test.  It doesn't test very many cases, and doesn't
26 // try to test the full functionality.  It just calls each function in the class and
27 // verifies that it works on a basic level.
28 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)29 void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
30 {
31     if (exec) logln("TestSuite DateTimePatternGeneratorAPI");
32     switch (index) {
33         TESTCASE(0, testAPI);
34         TESTCASE(1, testOptions);
35         TESTCASE(2, testAllFieldPatterns);
36         TESTCASE(3, testStaticGetSkeleton);
37         TESTCASE(4, testC);
38         TESTCASE(5, testSkeletonsWithDayPeriods);
39         default: name = ""; break;
40     }
41 }
42 
43 #define MAX_LOCALE   11
44 
45 /**
46  * Test various generic API methods of DateTimePatternGenerator for API coverage.
47  */
testAPI()48 void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
49 {
50     UnicodeString patternData[] = {
51         UnicodeString("yM"),        // 00
52         UnicodeString("yMMM"),      // 01
53         UnicodeString("yMd"),       // 02
54         UnicodeString("yMMMd"),     // 03
55         UnicodeString("Md"),        // 04
56         UnicodeString("MMMd"),      // 05
57         UnicodeString("MMMMd"),     // 06
58         UnicodeString("yQQQ"),      // 07
59         UnicodeString("hhmm"),      // 08
60         UnicodeString("HHmm"),      // 09
61         UnicodeString("jjmm"),      // 10
62         UnicodeString("mmss"),      // 11
63         UnicodeString("yyyyMMMM"),  // 12
64         UnicodeString("MMMEd"),     // 13
65         UnicodeString("Ed"),        // 14
66         UnicodeString("jmmssSSS"),  // 15
67         UnicodeString("JJmm"),      // 16
68         UnicodeString(),
69      };
70 
71     const char* testLocale[MAX_LOCALE][4] = {
72         {"en", "US", "", ""},                   // 0
73         {"en", "US", "", "calendar=japanese"},  // 1
74         {"de", "DE", "", ""},                   // 2
75         {"fi", "", "", ""},                     // 3
76         {"es", "", "", ""},                     // 4
77         {"ja", "", "", ""},                     // 5
78         {"ja", "", "", "calendar=japanese"},    // 6
79         {"zh", "Hans", "CN", ""},               // 7
80         {"zh", "TW", "", "calendar=roc"},       // 8
81         {"ru", "", "", ""},                     // 9
82         {"zh", "", "", "calendar=chinese"},    // 10
83      };
84 
85     // For Weds, Jan 13, 1999, 23:58:59
86     UnicodeString patternResults[] = {
87         // en_US                                              // 0 en_US
88         UnicodeString("1/1999"),                              // 00: yM
89         UnicodeString("Jan 1999"),                            // 01: yMMM
90         UnicodeString("1/13/1999"),                           // 02: yMd
91         UnicodeString("Jan 13, 1999"),                        // 03: yMMMd
92         UnicodeString("1/13"),                                // 04: Md
93         UnicodeString("Jan 13"),                              // 05: MMMd
94         UnicodeString("January 13"),                          // 06: MMMMd
95         UnicodeString("Q1 1999"),                             // 07: yQQQ
96         UnicodeString("11:58 PM"),                            // 08: hhmm
97         UnicodeString("23:58"),                               // 09: HHmm
98         UnicodeString("11:58 PM"),                            // 10: jjmm
99         UnicodeString("58:59"),                               // 11: mmss
100         UnicodeString("January 1999"),                        // 12: yyyyMMMM
101         UnicodeString("Wed, Jan 13"),                         // 13: MMMEd -> EEE, MMM d
102         UnicodeString("13 Wed"),                              // 14: Ed    -> d EEE
103         UnicodeString("11:58:59.123 PM"),                     // 15: jmmssSSS -> "h:mm:ss.SSS a"
104         UnicodeString("11:58"),                               // 16: JJmm
105 
106         // en_US@calendar=japanese                            // 1 en_US@calendar=japanese
107         UnicodeString("1/11 H"),                              //  0: yM
108         UnicodeString("Jan 11 Heisei"),                       //  1: yMMM
109         UnicodeString("1/13/11 H"),                           //  2: yMd
110         UnicodeString("Jan 13, 11 Heisei"),                   //  3: yMMMd
111         UnicodeString("1/13"),                                //  4: Md
112         UnicodeString("Jan 13"),                              //  5: MMMd
113         UnicodeString("January 13"),                          //  6: MMMMd
114         UnicodeString("Q1 11 Heisei"),                        //  7: yQQQ
115         UnicodeString("11:58 PM"),                            //  8: hhmm
116         UnicodeString("23:58"),                               //  9: HHmm
117         UnicodeString("11:58 PM"),                            // 10: jjmm
118         UnicodeString("58:59"),                               // 11: mmss
119         UnicodeString("January 11 Heisei"),                   // 12: yyyyMMMM
120         UnicodeString("Wed, Jan 13"),                         // 13: MMMEd -> EEE, MMM d"
121         UnicodeString("13 Wed"),                              // 14: Ed    -> d EEE
122         UnicodeString("11:58:59.123 PM"),                     // 15: jmmssSSS -> "h:mm:ss.SSS a"
123         UnicodeString("11:58"),                               // 16: JJmm
124 
125         // de_DE                                              // 2 de_DE
126         UnicodeString("1.1999"),                              // 00: yM
127         UnicodeString("Jan. 1999"),                           // 01: yMMM
128         UnicodeString("13.1.1999"),                           // 02: yMd
129         UnicodeString("13. Jan. 1999"),                       // 03: yMMMd
130         UnicodeString("13.1."),                               // 04: Md
131         UnicodeString("13. Jan."),                            // 05: MMMd
132         UnicodeString("13. Januar"),                          // 06: MMMMd
133         UnicodeString("Q1 1999"),                             // 07: yQQQ
134         UnicodeString("11:58 nachm."),                        // 08: hhmm
135         UnicodeString("23:58"),                               // 09: HHmm
136         UnicodeString("23:58"),                               // 10: jjmm
137         UnicodeString("58:59"),                               // 11: mmss
138         UnicodeString("Januar 1999"),                         // 12: yyyyMMMM
139         UnicodeString("Mi., 13. Jan."),                       // 13: MMMEd -> EEE, d. MMM
140         UnicodeString("Mi., 13."),                            // 14: Ed   -> EEE d.
141         UnicodeString("23:58:59,123"),                        // 15: jmmssSSS -> "HH:mm:ss,SSS"
142         UnicodeString("23:58"),                               // 16: JJmm
143 
144         // fi                                                 // 3 fi
145         UnicodeString("1.1999"),                              // 00: yM (fixed expected result per ticket:6626:)
146         UnicodeString("tammi 1999"),                          // 01: yMMM
147         UnicodeString("13.1.1999"),                           // 02: yMd
148         UnicodeString("13. tammik. 1999"),                    // 03: yMMMd
149         UnicodeString("13.1."),                               // 04: Md
150         UnicodeString("13. tammik."),                         // 05: MMMd
151         UnicodeString("13. tammikuuta"),                      // 06: MMMMd
152         UnicodeString("1. nelj. 1999"),                       // 07: yQQQ
153         UnicodeString("11.58 ip."),                           // 08: hhmm
154         UnicodeString("23.58"),                               // 09: HHmm
155         UnicodeString("23.58"),                               // 10: jjmm
156         UnicodeString("58.59"),                               // 11: mmss
157         UnicodeString("tammikuu 1999"),                       // 12: yyyyMMMM
158         UnicodeString("ke 13. tammik."),                      // 13: MMMEd -> EEE d. MMM
159         UnicodeString("ke 13."),                              // 14: Ed    -> ccc d.
160         UnicodeString("23.58.59,123"),                        // 15: jmmssSSS -> "H.mm.ss,SSS"
161         UnicodeString("23.58"),                               // 16: JJmm
162 
163         // es                                                 // 4 es
164         UnicodeString("1/1999"),                              // 00: yM    -> "M/y"
165         UnicodeString("ene. 1999"),                           // 01: yMMM  -> "MMM y"
166         UnicodeString("13/1/1999"),                           // 02: yMd   -> "d/M/y"
167         UnicodeString("13 ene. 1999"),                        // 03: yMMMd -> "d MMM y"
168         UnicodeString("13/1"),                                // 04: Md    -> "d/M"
169         UnicodeString("13 ene."),                             // 05: MMMd  -> "d 'de' MMM"
170         UnicodeString("13 de enero"),                         // 06: MMMMd -> "d 'de' MMMM"
171         UnicodeString("T1 1999"),                             // 07: yQQQ  -> "QQQ y"
172         UnicodeString("11:58 p. m."),                         // 08: hhmm  -> "hh:mm a"
173         UnicodeString("23:58"),                               // 09: HHmm  -> "HH:mm"
174         UnicodeString("23:58"),                               // 10: jjmm  -> "HH:mm"
175         UnicodeString("58:59"),                               // 11: mmss  -> "mm:ss"
176         UnicodeString("enero de 1999"),                       // 12: yyyyMMMM -> "MMMM 'de' yyyy"
177         CharsToUnicodeString("mi\\u00E9., 13 ene."),          // 13: MMMEd -> "E, d MMM"
178         CharsToUnicodeString("mi\\u00E9. 13"),                // 14: Ed    -> "EEE d"
179         UnicodeString("23:58:59,123"),                        // 15: jmmssSSS -> "H:mm:ss,SSS"
180         UnicodeString("23:58"),                               // 16: JJmm
181 
182         // ja                                                             // 5 ja
183         UnicodeString("1999/1"),                                          // 00: yM    -> y/M
184         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 01: yMMM  -> y\u5E74M\u6708
185         UnicodeString("1999/1/13"),                                       // 02: yMd   -> y/M/d
186         CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),             // 03: yMMMd -> y\u5E74M\u6708d\u65E5
187         UnicodeString("1/13"),                                            // 04: Md    -> M/d
188         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5
189         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
190         CharsToUnicodeString("1999/Q1"),                                  // 07: yQQQ  -> y/QQQ
191         CharsToUnicodeString("\\u5348\\u5F8C11:58"),                      // 08: hhmm
192         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm
193         UnicodeString("23:58"),                                           // 10: jjmm
194         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss
195         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 12: yyyyMMMM  -> y\u5E74M\u6708
196         CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"),               // 13: MMMEd -> M\u6708d\u65E5(EEE)
197         CharsToUnicodeString("13\\u65E5(\\u6C34)"),                       // 14: Ed    -> d\u65E5(EEE)
198         UnicodeString("23:58:59.123"),                                    // 15: jmmssSSS -> "H:mm:ss.SSS"
199         UnicodeString("23:58"),                                           // 16: JJmm
200 
201         // ja@calendar=japanese                                           // 6 ja@calendar=japanese
202         CharsToUnicodeString("\\u5E73\\u621011/1"),                       // 00: yM    -> Gy/m
203         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"),          // 01: yMMM  -> Gy\u5E74M\u6708
204         CharsToUnicodeString("\\u5E73\\u621011/1/13"),                    // 02: yMd   -> Gy/m/d
205         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
206         UnicodeString("1/13"),                                            // 04: Md    -> M/d
207         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5
208         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
209         CharsToUnicodeString("\\u5E73\\u621011/Q1"),                     // 07: yQQQ  -> Gy/QQQ
210         CharsToUnicodeString("\\u5348\\u5F8C11:58"),                      // 08: hhmm  ->
211         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm          (as for ja)
212         UnicodeString("23:58"),                                           // 10: jjmm
213         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss          (as for ja)
214         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"),          // 12: yyyyMMMM  -> Gyyyy\u5E74M\u6708
215         CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"),               // 13: MMMEd -> M\u6708d\u65E5(EEE)
216         CharsToUnicodeString("13\\u65E5(\\u6C34)"),                       // 14: Ed    -> d\u65E5(EEE)
217         UnicodeString("23:58:59.123"),                                    // 15: jmmssSSS -> "H:mm:ss.SSS"
218         UnicodeString("23:58"),                                           // 16: JJmm
219 
220         // zh_Hans_CN                                                     // 7 zh_Hans_CN
221         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 00: yM -> y\u5E74M\u6708
222         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 01: yMMM  -> yyyy\u5E74MMM (fixed expected result per ticket:6626:)
223         CharsToUnicodeString("1999/1/13"),                                // 02: yMd
224         CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),             // 03: yMMMd -> yyyy\u5E74MMMd\u65E5 (fixed expected result per ticket:6626:)
225         UnicodeString("1/13"),                                            // 04: Md
226         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5 (fixed expected result per ticket:6626:)
227         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
228         CharsToUnicodeString("1999\\u5E74\\u7B2C1\\u5B63\\u5EA6"),        // 07: yQQQ
229         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 08: hhmm
230         UnicodeString("23:58"),                                           // 09: HHmm
231         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 10: jjmm
232         UnicodeString("58:59"),                                           // 11: mmss
233         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 12: yyyyMMMM  -> yyyy\u5E74MMM
234         CharsToUnicodeString("1\\u670813\\u65E5\\u5468\\u4E09"),          // 13: MMMEd -> MMMd\u65E5EEE
235         CharsToUnicodeString("13\\u65E5\\u5468\\u4E09"),                  // 14: Ed    -> d\u65E5EEE
236         CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"),               // 15: jmmssSSS -> "ah:mm:ss.SSS"
237         UnicodeString("11:58"),                                           // 16: JJmm
238 
239         // zh_TW@calendar=roc                                             // 8 zh_TW@calendar=roc
240         CharsToUnicodeString("\\u6C11\\u570B88/1"),                       // 00: yM    -> Gy/M
241         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"),          // 01: yMMM  -> Gy\u5E74M\u6708
242         CharsToUnicodeString("\\u6C11\\u570B88/1/13"),                    // 02: yMd   -> Gy/M/d
243         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
244         UnicodeString("1/13"),                                            // 04: Md    -> M/d
245         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  ->M\u6708d\u65E5
246         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  ->M\u6708d\u65E5
247         CharsToUnicodeString("\\u6C11\\u570B88\\u5E74\\u7B2C1\\u5B63"),   // 07: yQQQ  -> Gy QQQ
248         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 08: hhmm  ->
249         UnicodeString("23:58"),                                           // 09: HHmm  ->
250         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 10: jjmm
251         UnicodeString("58:59"),                                           // 11: mmss  ->
252         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"),          // 12: yyyyMMMM  -> Gy\u5E74M\u670
253         CharsToUnicodeString("1\\u670813\\u65E5\\u9031\\u4E09"),          // 13: MMMEd -> M\u6708d\u65E5EEE
254         CharsToUnicodeString("13 \\u9031\\u4E09"),                        // 14: Ed    -> d E
255         CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"),               // 15: jmmssSSS -> "ah:mm:ss.SSS"
256         UnicodeString("11:58"),                                           // 16: JJmm
257 
258         // ru                                                             // 9 ru
259         UnicodeString("01.1999"),                                         // 00: yM    -> MM.y
260         CharsToUnicodeString("\\u044F\\u043D\\u0432. 1999 \\u0433."),     // 01: yMMM  -> LLL y
261         UnicodeString("13.01.1999"),                                      // 02: yMd   -> dd.MM.y
262         CharsToUnicodeString("13 \\u044F\\u043D\\u0432. 1999 \\u0433."),  // 03: yMMMd -> d MMM y
263         UnicodeString("13.01"),                                           // 04: Md    -> dd.MM
264         CharsToUnicodeString("13 \\u044F\\u043D\\u0432."),                // 05: MMMd  -> d MMM
265         CharsToUnicodeString("13 \\u044F\\u043D\\u0432\\u0430\\u0440\\u044F"), // 06: MMMMd  -> d MMMM
266         CharsToUnicodeString("1-\\u0439 \\u043A\\u0432. 1999 \\u0433."),  // 07: yQQQ  -> y QQQ
267         CharsToUnicodeString("11:58 PM"),                                 // 08: hhmm  -> hh:mm a
268         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm
269         UnicodeString("23:58"),                                           // 10: jjmm  -> HH:mm
270         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss
271         CharsToUnicodeString("\\u044F\\u043D\\u0432\\u0430\\u0440\\u044C 1999 \\u0433."), // 12: yyyyMMMM -> LLLL y
272         CharsToUnicodeString("\\u0441\\u0440, 13 \\u044F\\u043D\\u0432."), // 13: MMMEd -> ccc, d MMM
273         CharsToUnicodeString("\\u0441\\u0440, 13"),                       // 14: Ed    -> EEE, d
274         UnicodeString("23:58:59,123"),                                    // 15: jmmssSSS -> "H:mm:ss,SSS"
275         UnicodeString("23:58"),                                           // 16: JJmm
276 
277         // zh@calendar=chinese                                            // 10 zh@calendar=chinese
278         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 00: yMMM
279         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 01: yMMM
280         CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"),             // 02: yMMMd
281         CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"),             // 03: yMMMd
282         UnicodeString("11-26"),                                                 // 04: Md
283         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"),                 // 05: MMMd
284         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"),                 // 06: MMMMd
285         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u7b2c\\u56db\\u5B63\\u5EA6"),  // 07: yQQQ
286         CharsToUnicodeString("\\u4E0B\\u534811:58"),                            // 08: hhmm
287         UnicodeString("23:58"),                                                 // 09: HHmm
288         CharsToUnicodeString("\\u4E0B\\u534811:58"),                            // 10: jjmm
289         UnicodeString("58:59"),                                                 // 11: mmss
290         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 12: yyyyMMMM
291         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5\\u5468\\u4E09"),   // 13: MMMEd
292         CharsToUnicodeString("26\\u65E5\\u5468\\u4E09"),                        // 14: Ed    -> d\u65E5EEE
293         CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"),                     // 15: jmmssSS
294         UnicodeString("11:58"),                                                 // 16: JJmm
295 
296         UnicodeString(),
297     };
298 
299     UnicodeString patternTests2[] = {
300         UnicodeString("yyyyMMMdd"),
301         UnicodeString("yyyyqqqq"),
302         UnicodeString("yMMMdd"),
303         UnicodeString("EyyyyMMMdd"),
304         UnicodeString("yyyyMMdd"),
305         UnicodeString("yyyyMMM"),
306         UnicodeString("yyyyMM"),
307         UnicodeString("yyMM"),
308         UnicodeString("yMMMMMd"),
309         UnicodeString("EEEEEMMMMMd"),
310         UnicodeString("MMMd"),
311         UnicodeString("MMMdhmm"),
312         UnicodeString("EMMMdhmms"),
313         UnicodeString("MMdhmm"),
314         UnicodeString("EEEEMMMdhmms"),
315         UnicodeString("yyyyMMMddhhmmss"),
316         UnicodeString("EyyyyMMMddhhmmss"),
317         UnicodeString("hmm"),
318         UnicodeString("hhmm"),
319         UnicodeString("hhmmVVVV"),
320         UnicodeString(""),
321     };
322     UnicodeString patternResults2[] = {
323         UnicodeString("Oct 14, 1999"),
324         UnicodeString("4th quarter 1999"),
325         UnicodeString("Oct 14, 1999"),
326         UnicodeString("Thu, Oct 14, 1999"),
327         UnicodeString("10/14/1999"),
328         UnicodeString("Oct 1999"),
329         UnicodeString("10/1999"),
330         UnicodeString("10/99"),
331         UnicodeString("O 14, 1999"),
332         UnicodeString("T, O 14"),
333         UnicodeString("Oct 14"),
334         UnicodeString("Oct 14, 6:58 AM"),
335         UnicodeString("Thu, Oct 14, 6:58:59 AM"),
336         UnicodeString("10/14, 6:58 AM"),
337         UnicodeString("Thursday, Oct 14, 6:58:59 AM"),
338         UnicodeString("Oct 14, 1999, 6:58:59 AM"),
339         UnicodeString("Thu, Oct 14, 1999, 6:58:59 AM"),
340         UnicodeString("6:58 AM"),
341         UnicodeString("6:58 AM"),
342         UnicodeString("6:58 AM GMT"),
343         UnicodeString(""),
344     };
345 
346     // results for getSkeletons() and getPatternForSkeleton()
347     const UnicodeString testSkeletonsResults[] = {
348         UnicodeString("HH:mm"),
349         UnicodeString("MMMMd"),
350         UnicodeString("MMMMMdd"),
351     };
352 
353     const UnicodeString testBaseSkeletonsResults[] = {
354         UnicodeString("Hm"),
355         UnicodeString("MMMMd"),
356         UnicodeString("MMMMMd"),
357     };
358 
359     const char* testGetSkeletonAndBase[][3] = {
360         // pattern       skeleton    baseSkeleton
361         { "dd-MMM",     "MMMdd",    "MMMd" },
362         { "dd/MMMM/yy", "yyMMMMdd", "yMMMMd" },
363         { "h",          "h",        "h" },
364         { "ah",         "ah",       "ah" },
365         { "aaaah",      "aaaah",    "aaaah" },
366         { "Bh",         "Bh",       "Bh" }
367     };
368 
369     UnicodeString newDecimal(" "); // space
370     UnicodeString newAppendItemName("hrs.");
371     UnicodeString newAppendItemFormat("{1} {0}");
372     UnicodeString newDateTimeFormat("{1} {0}");
373     UErrorCode status = U_ZERO_ERROR;
374     UnicodeString conflictingPattern;
375     UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
376     (void)conflictingStatus;   // Suppress set but not used warning.
377 
378     // ======= Test CreateInstance with default locale
379     logln("Testing DateTimePatternGenerator createInstance from default locale");
380 
381     DateTimePatternGenerator *instFromDefaultLocale=DateTimePatternGenerator::createInstance(status);
382     if (U_FAILURE(status)) {
383         dataerrln("ERROR: Could not create DateTimePatternGenerator (default) - exitting");
384         return;
385     }
386     else {
387         delete instFromDefaultLocale;
388     }
389 
390     // ======= Test CreateInstance with given locale
391     logln("Testing DateTimePatternGenerator createInstance from French locale");
392     status = U_ZERO_ERROR;
393     DateTimePatternGenerator *instFromLocale=DateTimePatternGenerator::createInstance(Locale::getFrench(), status);
394     if (U_FAILURE(status)) {
395         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
396         return;
397     }
398 
399     // ======= Test clone DateTimePatternGenerator
400     logln("Testing DateTimePatternGenerator::clone()");
401     status = U_ZERO_ERROR;
402 
403 
404     UnicodeString decimalSymbol = instFromLocale->getDecimal();
405     UnicodeString newDecimalSymbol = UnicodeString("*");
406     decimalSymbol = instFromLocale->getDecimal();
407     instFromLocale->setDecimal(newDecimalSymbol);
408     DateTimePatternGenerator *cloneDTPatternGen=instFromLocale->clone();
409     decimalSymbol = cloneDTPatternGen->getDecimal();
410     if (decimalSymbol != newDecimalSymbol) {
411         errln("ERROR: inconsistency is found in cloned object.");
412     }
413     if ( !(*cloneDTPatternGen == *instFromLocale) ) {
414         errln("ERROR: inconsistency is found in cloned object.");
415     }
416 
417     if ( *cloneDTPatternGen != *instFromLocale ) {
418         errln("ERROR: inconsistency is found in cloned object.");
419     }
420 
421     delete instFromLocale;
422     delete cloneDTPatternGen;
423 
424     // ======= Test simple use cases
425     logln("Testing simple use cases");
426     status = U_ZERO_ERROR;
427     Locale deLocale=Locale::getGermany();
428     UDate sampleDate=LocaleTest::date(99, 9, 13, 23, 58, 59);
429     DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(deLocale, status);
430     if (U_FAILURE(status)) {
431         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getGermany()) - exitting");
432         return;
433     }
434     UnicodeString findPattern = gen->getBestPattern(UnicodeString("MMMddHmm"), status);
435     SimpleDateFormat *format = new SimpleDateFormat(findPattern, deLocale, status);
436     if (U_FAILURE(status)) {
437         dataerrln("ERROR: Could not create SimpleDateFormat (Locale::getGermany())");
438         delete gen;
439         return;
440     }
441     TimeZone *zone = TimeZone::createTimeZone(UnicodeString("ECT"));
442     if (zone==NULL) {
443         dataerrln("ERROR: Could not create TimeZone ECT");
444         delete gen;
445         delete format;
446         return;
447     }
448     format->setTimeZone(*zone);
449     UnicodeString dateReturned, expectedResult;
450     dateReturned.remove();
451     dateReturned = format->format(sampleDate, dateReturned, status);
452     expectedResult=UnicodeString("14. Okt., 08:58", -1, US_INV);
453     if ( dateReturned != expectedResult ) {
454         errln("ERROR: Simple test in getBestPattern with Locale::getGermany()).");
455     }
456     // add new pattern
457     status = U_ZERO_ERROR;
458     conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM", -1, US_INV), true, conflictingPattern, status);
459     if (U_FAILURE(status)) {
460         errln("ERROR: Could not addPattern - d\'. von\' MMMM");
461     }
462     status = U_ZERO_ERROR;
463     UnicodeString testPattern=gen->getBestPattern(UnicodeString("MMMMdd"), status);
464     testPattern=gen->getBestPattern(UnicodeString("MMMddHmm"), status);
465     format->applyPattern(gen->getBestPattern(UnicodeString("MMMMdHmm"), status));
466     dateReturned.remove();
467     dateReturned = format->format(sampleDate, dateReturned, status);
468     expectedResult=UnicodeString("14. von Oktober, 08:58", -1, US_INV);
469     if ( dateReturned != expectedResult ) {
470         errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM   Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
471     }
472     delete format;
473 
474     // get a pattern and modify it
475     format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
476                                                                   deLocale);
477     format->setTimeZone(*zone);
478     UnicodeString pattern;
479     pattern = format->toPattern(pattern);
480     dateReturned.remove();
481     dateReturned = format->format(sampleDate, dateReturned, status);
482     expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Sommerzeit");
483     if ( dateReturned != expectedResult ) {
484         errln("ERROR: Simple test uses full date format.");
485         errln(UnicodeString(" Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
486     }
487 
488     // modify it to change the zone.
489     UnicodeString newPattern = gen->replaceFieldTypes(pattern, UnicodeString("vvvv"), status);
490     format->applyPattern(newPattern);
491     dateReturned.remove();
492     dateReturned = format->format(sampleDate, dateReturned, status);
493     expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Zeit");
494     if ( dateReturned != expectedResult ) {
495         errln("ERROR: Simple test modify the timezone!");
496         errln(UnicodeString(" Got: ")+ dateReturned + UnicodeString(" Expected: ") + expectedResult);
497     }
498 
499     // setDeciaml(), getDeciaml()
500     gen->setDecimal(newDecimal);
501     if (newDecimal != gen->getDecimal()) {
502         errln("ERROR: unexpected result from setDecimal() and getDecimal()!.\n");
503     }
504 
505     // setAppenItemName() , getAppendItemName()
506     gen->setAppendItemName(UDATPG_HOUR_FIELD, newAppendItemName);
507     if (newAppendItemName != gen->getAppendItemName(UDATPG_HOUR_FIELD)) {
508         errln("ERROR: unexpected result from setAppendItemName() and getAppendItemName()!.\n");
509     }
510 
511     // setAppenItemFormat() , getAppendItemFormat()
512     gen->setAppendItemFormat(UDATPG_HOUR_FIELD, newAppendItemFormat);
513     if (newAppendItemFormat != gen->getAppendItemFormat(UDATPG_HOUR_FIELD)) {
514         errln("ERROR: unexpected result from setAppendItemFormat() and getAppendItemFormat()!.\n");
515     }
516 
517     // setDateTimeFormat() , getDateTimeFormat()
518     gen->setDateTimeFormat(newDateTimeFormat);
519     if (newDateTimeFormat != gen->getDateTimeFormat()) {
520         errln("ERROR: unexpected result from setDateTimeFormat() and getDateTimeFormat()!.\n");
521     }
522 
523     // ======== Test getSkeleton and getBaseSkeleton
524 
525     int32_t i, count = UPRV_LENGTHOF(testGetSkeletonAndBase);
526     for (i = 0; i < count; i++) {
527         status = U_ZERO_ERROR;
528         pattern                            = UnicodeString(testGetSkeletonAndBase[i][0]);
529         UnicodeString expectedSkeleton     = UnicodeString(testGetSkeletonAndBase[i][1]);
530         UnicodeString expectedBaseSkeleton = UnicodeString(testGetSkeletonAndBase[i][2]);
531         UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
532 		if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
533 			 errln("ERROR: Unexpected result from getSkeleton().\n");
534 			 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
535 		}
536 		retSkeleton = gen->getBaseSkeleton(pattern, status);
537 		if(U_FAILURE(status) || retSkeleton !=  expectedBaseSkeleton) {
538 			 errln("ERROR: Unexpected result from getBaseSkeleton().\n");
539 			 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
540 		}
541     }
542 
543     delete format;
544     delete zone;
545     delete gen;
546 
547     {
548         // Trac# 6104
549         status = U_ZERO_ERROR;
550         pattern = UnicodeString("YYYYMMM");
551         UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
552         Locale loc("ja");
553         UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
554         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
555         if(U_FAILURE(status)) {
556             dataerrln("ERROR: Could not create DateTimePatternGenerator");
557             return;
558         }
559         UnicodeString bPattern = patGen->getBestPattern(pattern, status);
560         UnicodeString rDate;
561         SimpleDateFormat sdf(bPattern, loc, status);
562         rDate.remove();
563         rDate = sdf.format(testDate1, rDate);
564 
565         logln(UnicodeString(" ja locale with skeleton: YYYYMMM  Best Pattern:") + bPattern);
566         logln(UnicodeString("  Formatted date:") + rDate);
567 
568         if ( expR!= rDate ) {
569             errln(UnicodeString("\nERROR: Test Japanese month hack Got: ") + rDate +
570                   UnicodeString(" Expected: ") + expR );
571         }
572 
573         delete patGen;
574     }
575     {   // Trac# 6104
576         Locale loc("zh");
577         UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
578         UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
579         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
580         if(U_FAILURE(status)) {
581             dataerrln("ERROR: Could not create DateTimePatternGenerator");
582             return;
583         }
584         UnicodeString bPattern = patGen->getBestPattern(pattern, status);
585         UnicodeString rDate;
586         SimpleDateFormat sdf(bPattern, loc, status);
587         rDate.remove();
588         rDate = sdf.format(testDate1, rDate);
589 
590         logln(UnicodeString(" zh locale with skeleton: YYYYMMM  Best Pattern:") + bPattern);
591         logln(UnicodeString("  Formatted date:") + rDate);
592         if ( expR!= rDate ) {
593             errln(UnicodeString("\nERROR: Test Chinese month hack Got: ") + rDate +
594                   UnicodeString(" Expected: ") + expR );
595         }
596         delete patGen;
597     }
598 
599     {
600          // Trac# 6172 duplicate time pattern
601          status = U_ZERO_ERROR;
602          pattern = UnicodeString("hmv");
603          UnicodeString expR = UnicodeString("h:mm a v"); // avail formats has hm -> "h:mm a" (fixed expected result per ticket:6626:)
604          Locale loc("en");
605          DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
606          if(U_FAILURE(status)) {
607              dataerrln("ERROR: Could not create DateTimePatternGenerator");
608              return;
609          }
610          UnicodeString bPattern = patGen->getBestPattern(pattern, status);
611          logln(UnicodeString(" en locale with skeleton: hmv  Best Pattern:") + bPattern);
612 
613          if ( expR!= bPattern ) {
614              errln(UnicodeString("\nERROR: Test EN time format Got: ") + bPattern +
615                    UnicodeString(" Expected: ") + expR );
616          }
617 
618          delete patGen;
619      }
620 
621 
622     // ======= Test various skeletons.
623     logln("Testing DateTimePatternGenerator with various skeleton");
624 
625     status = U_ZERO_ERROR;
626     int32_t localeIndex=0;
627     int32_t resultIndex=0;
628     UnicodeString resultDate;
629     UDate testDate= LocaleTest::date(99, 0, 13, 23, 58, 59) + 123.0;
630     while (localeIndex < MAX_LOCALE )
631     {
632         int32_t dataIndex=0;
633         UnicodeString bestPattern;
634 
635         Locale loc(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
636         logln("\n\n Locale: %s_%s_%s@%s", testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
637         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
638         if(U_FAILURE(status)) {
639             dataerrln("ERROR: Could not create DateTimePatternGenerator with locale index:%d . - exitting\n", localeIndex);
640             return;
641         }
642         while (patternData[dataIndex].length() > 0) {
643             log(patternData[dataIndex]);
644             bestPattern = patGen->getBestPattern(patternData[dataIndex++], status);
645             logln(UnicodeString(" -> ") + bestPattern);
646 
647             SimpleDateFormat sdf(bestPattern, loc, status);
648             resultDate.remove();
649             resultDate = sdf.format(testDate, resultDate);
650             if ( resultDate != patternResults[resultIndex] ) {
651                 errln(UnicodeString("\nERROR: Test various skeletons[") + (dataIndex-1) + UnicodeString("], localeIndex ") + localeIndex +
652                       UnicodeString(". Got: \"") + resultDate + UnicodeString("\" Expected: \"") + patternResults[resultIndex] + "\"" );
653             }
654 
655             resultIndex++;
656         }
657         delete patGen;
658         localeIndex++;
659     }
660 
661     // ======= More tests ticket#6110
662     logln("Testing DateTimePatternGenerator with various skeleton");
663 
664     status = U_ZERO_ERROR;
665     localeIndex=0;
666     resultIndex=0;
667     testDate= LocaleTest::date(99, 9, 13, 23, 58, 59);
668     {
669         int32_t dataIndex=0;
670         UnicodeString bestPattern;
671         logln("\n\n Test various skeletons for English locale...");
672         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(Locale::getEnglish(), status);
673         if(U_FAILURE(status)) {
674             dataerrln("ERROR: Could not create DateTimePatternGenerator with locale English . - exitting\n");
675             return;
676         }
677         TimeZone *enZone = TimeZone::createTimeZone(UnicodeString("ECT/GMT"));
678         if (enZone==NULL) {
679             dataerrln("ERROR: Could not create TimeZone ECT");
680             delete patGen;
681             return;
682         }
683         SimpleDateFormat *enFormat = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull,
684                          DateFormat::kFull, Locale::getEnglish());
685         enFormat->setTimeZone(*enZone);
686         while (patternTests2[dataIndex].length() > 0) {
687             logln(patternTests2[dataIndex]);
688             bestPattern = patGen->getBestPattern(patternTests2[dataIndex], status);
689             logln(UnicodeString(" -> ") + bestPattern);
690             enFormat->applyPattern(bestPattern);
691             resultDate.remove();
692             resultDate = enFormat->format(testDate, resultDate);
693             if ( resultDate != patternResults2[resultIndex] ) {
694                 errln(UnicodeString("\nERROR: Test various skeletons[") + dataIndex
695                     + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") +
696                     patternResults2[resultIndex] );
697             }
698             dataIndex++;
699             resultIndex++;
700         }
701         delete patGen;
702         delete enZone;
703         delete enFormat;
704     }
705 
706 
707 
708     // ======= Test random skeleton
709     DateTimePatternGenerator *randDTGen= DateTimePatternGenerator::createInstance(status);
710     if (U_FAILURE(status)) {
711         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
712         return;
713     }
714     UChar newChar;
715     for (i=0; i<10; ++i) {
716         UnicodeString randomSkeleton;
717         int32_t len = rand() % 20;
718         for (int32_t j=0; j<len; ++j ) {
719             while ((newChar = (UChar)(rand()%0x7f))>=(UChar)0x20) {
720                 randomSkeleton += newChar;
721             }
722         }
723         UnicodeString bestPattern = randDTGen->getBestPattern(randomSkeleton, status);
724     }
725     delete randDTGen;
726 
727     // UnicodeString randomString=Unicode
728     // ======= Test getStaticClassID()
729 
730     logln("Testing getStaticClassID()");
731     status = U_ZERO_ERROR;
732     DateTimePatternGenerator *test= DateTimePatternGenerator::createInstance(status);
733 
734     if(test->getDynamicClassID() != DateTimePatternGenerator::getStaticClassID()) {
735         errln("ERROR: getDynamicClassID() didn't return the expected value");
736     }
737     delete test;
738 
739     // ====== Test createEmptyInstance()
740 
741     logln("Testing createEmptyInstance()");
742     status = U_ZERO_ERROR;
743 
744     test = DateTimePatternGenerator::createEmptyInstance(status);
745     if(U_FAILURE(status)) {
746          errln("ERROR: Fail to create an empty instance ! - exitting.\n");
747          delete test;
748          return;
749     }
750 
751     conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status);
752     status = U_ZERO_ERROR;
753     testPattern=test->getBestPattern(UnicodeString("MMMMdd"), status);
754     conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status);
755     conflictingStatus = test->addPattern(UnicodeString("MMMMMdd"), true, conflictingPattern, status); //duplicate pattern
756     StringEnumeration *output=NULL;
757     output = test->getRedundants(status);
758     expectedResult=UnicodeString("MMMMd");
759     if (output != NULL) {
760         output->reset(status);
761         const UnicodeString *dupPattern=output->snext(status);
762         if ( (dupPattern==NULL) || (*dupPattern != expectedResult) ) {
763             errln("ERROR: Fail in getRedundants !\n");
764         }
765     }
766 
767     // ======== Test getSkeletons and getBaseSkeletons
768     StringEnumeration* ptrSkeletonEnum = test->getSkeletons(status);
769     if(U_FAILURE(status)) {
770         errln("ERROR: Fail to get skeletons !\n");
771     }
772     UnicodeString returnPattern, *ptrSkeleton;
773     ptrSkeletonEnum->reset(status);
774     count=ptrSkeletonEnum->count(status);
775     for (i=0; i<count; ++i) {
776         ptrSkeleton = (UnicodeString *)ptrSkeletonEnum->snext(status);
777         returnPattern = test->getPatternForSkeleton(*ptrSkeleton);
778         if ( returnPattern != testSkeletonsResults[i] ) {
779             errln(UnicodeString("ERROR: Unexpected result from getSkeletons and getPatternForSkeleton\nGot: ") + returnPattern
780                + UnicodeString("\nExpected: ") + testSkeletonsResults[i]
781                + UnicodeString("\n"));
782         }
783     }
784     StringEnumeration* ptrBaseSkeletonEnum = test->getBaseSkeletons(status);
785     if(U_FAILURE(status)) {
786         errln("ERROR: Fail to get base skeletons !\n");
787     }
788     count=ptrBaseSkeletonEnum->count(status);
789     for (i=0; i<count; ++i) {
790         ptrSkeleton = (UnicodeString *)ptrBaseSkeletonEnum->snext(status);
791         if ( *ptrSkeleton != testBaseSkeletonsResults[i] ) {
792             errln("ERROR: Unexpected result from getBaseSkeletons() !\n");
793         }
794     }
795 
796     // ========= DateTimePatternGenerator sample code in Userguide
797     // set up the generator
798     Locale locale = Locale::getFrench();
799     status = U_ZERO_ERROR;
800     DateTimePatternGenerator *generator = DateTimePatternGenerator::createInstance( locale, status);
801 
802     // get a pattern for an abbreviated month and day
803     pattern = generator->getBestPattern(UnicodeString("MMMd"), status);
804     SimpleDateFormat formatter(pattern, locale, status);
805 
806     zone = TimeZone::createTimeZone(UnicodeString("GMT"));
807     formatter.setTimeZone(*zone);
808     // use it to format (or parse)
809     UnicodeString formatted;
810     formatted = formatter.format(Calendar::getNow(), formatted, status);
811     // for French, the result is "13 sept."
812     formatted.remove();
813     // cannot use the result from getNow() because the value change evreyday.
814     testDate= LocaleTest::date(99, 0, 13, 23, 58, 59);
815     formatted = formatter.format(testDate, formatted, status);
816     expectedResult=UnicodeString("14 janv.");
817     if ( formatted != expectedResult ) {
818         errln("ERROR: Userguide sample code result!");
819         errln(UnicodeString(" Got: ")+ formatted + UnicodeString(" Expected: ") + expectedResult);
820     }
821 
822     delete zone;
823     delete output;
824     delete ptrSkeletonEnum;
825     delete ptrBaseSkeletonEnum;
826     delete test;
827     delete generator;
828 }
829 
830 /**
831  * Test handling of options
832  *
833  * For reference, as of ICU 4.3.3,
834  *  root/gregorian has
835  *      Hm{"H:mm"}
836  *      Hms{"H:mm:ss"}
837  *      hm{"h:mm a"}
838  *      hms{"h:mm:ss a"}
839  *  en/gregorian has
840  *      Hm{"H:mm"}
841  *      Hms{"H:mm:ss"}
842  *      hm{"h:mm a"}
843  *  be/gregorian has
844  *      HHmmss{"HH.mm.ss"}
845  *      Hm{"HH.mm"}
846  *      hm{"h.mm a"}
847  *      hms{"h.mm.ss a"}
848  */
849 typedef struct DTPtnGenOptionsData {
850     const char *locale;
851     const char *skel;
852     const char *expectedPattern;
853     UDateTimePatternMatchOptions    options;
854 } DTPtnGenOptionsData;
testOptions()855 void IntlTestDateTimePatternGeneratorAPI::testOptions(/*char *par*/)
856 {
857     DTPtnGenOptionsData testData[] = {
858     //   locale  skel   expectedPattern     options
859         { "en", "Hmm",  "HH:mm",   UDATPG_MATCH_NO_OPTIONS        },
860         { "en", "HHmm", "HH:mm",   UDATPG_MATCH_NO_OPTIONS        },
861         { "en", "hhmm", "h:mm a",  UDATPG_MATCH_NO_OPTIONS        },
862         { "en", "Hmm",  "HH:mm",   UDATPG_MATCH_HOUR_FIELD_LENGTH },
863         { "en", "HHmm", "HH:mm",   UDATPG_MATCH_HOUR_FIELD_LENGTH },
864         { "en", "hhmm", "hh:mm a", UDATPG_MATCH_HOUR_FIELD_LENGTH },
865         { "da", "Hmm",  "HH.mm",   UDATPG_MATCH_NO_OPTIONS        },
866         { "da", "HHmm", "HH.mm",   UDATPG_MATCH_NO_OPTIONS        },
867         { "da", "hhmm", "h.mm a",  UDATPG_MATCH_NO_OPTIONS        },
868         { "da", "Hmm",  "H.mm",    UDATPG_MATCH_HOUR_FIELD_LENGTH },
869         { "da", "HHmm", "HH.mm",   UDATPG_MATCH_HOUR_FIELD_LENGTH },
870         { "da", "hhmm", "hh.mm a", UDATPG_MATCH_HOUR_FIELD_LENGTH },
871         //
872         { "en",                   "yyyy",  "yyyy",  UDATPG_MATCH_NO_OPTIONS },
873         { "en",                   "YYYY",  "YYYY",  UDATPG_MATCH_NO_OPTIONS },
874         { "en",                   "U",     "y",     UDATPG_MATCH_NO_OPTIONS },
875         { "en@calendar=japanese", "yyyy",  "y G",   UDATPG_MATCH_NO_OPTIONS },
876         { "en@calendar=japanese", "YYYY",  "Y G",   UDATPG_MATCH_NO_OPTIONS },
877         { "en@calendar=japanese", "U",     "y G",   UDATPG_MATCH_NO_OPTIONS },
878         { "en@calendar=chinese",  "yyyy",  "r(U)",  UDATPG_MATCH_NO_OPTIONS },
879         { "en@calendar=chinese",  "YYYY",  "Y(Y)",  UDATPG_MATCH_NO_OPTIONS }, // not a good result, want r(Y) or r(U)
880         { "en@calendar=chinese",  "U",     "r(U)",     UDATPG_MATCH_NO_OPTIONS },
881         { "en@calendar=chinese",  "Gy",    "r(U)",     UDATPG_MATCH_NO_OPTIONS },
882         { "en@calendar=chinese",  "GU",    "r(U)",     UDATPG_MATCH_NO_OPTIONS },
883         { "en@calendar=chinese",  "ULLL",  "MMM U",    UDATPG_MATCH_NO_OPTIONS },
884         { "en@calendar=chinese",  "yMMM",  "MMM r(U)", UDATPG_MATCH_NO_OPTIONS },
885         { "en@calendar=chinese",  "GUMMM", "MMM r(U)", UDATPG_MATCH_NO_OPTIONS },
886         { "zh@calendar=chinese",  "yyyy",  "rU\\u5E74",    UDATPG_MATCH_NO_OPTIONS },
887         { "zh@calendar=chinese",  "YYYY",  "YY\\u5E74",    UDATPG_MATCH_NO_OPTIONS }, // not a good result, may want r(Y) or r(U)
888         { "zh@calendar=chinese",  "U",     "rU\\u5E74",    UDATPG_MATCH_NO_OPTIONS },
889         { "zh@calendar=chinese",  "Gy",    "rU\\u5E74",    UDATPG_MATCH_NO_OPTIONS },
890         { "zh@calendar=chinese",  "GU",    "rU\\u5E74",    UDATPG_MATCH_NO_OPTIONS },
891         { "zh@calendar=chinese",  "ULLL",  "U\\u5E74MMM",  UDATPG_MATCH_NO_OPTIONS },
892         { "zh@calendar=chinese",  "yMMM",  "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS },
893         { "zh@calendar=chinese",  "GUMMM", "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS },
894     };
895 
896     int count = UPRV_LENGTHOF(testData);
897     const DTPtnGenOptionsData * testDataPtr = testData;
898 
899     for (; count-- > 0; ++testDataPtr) {
900         UErrorCode status = U_ZERO_ERROR;
901 
902         Locale locale(testDataPtr->locale);
903         UnicodeString skel(testDataPtr->skel);
904         UnicodeString expectedPattern(UnicodeString(testDataPtr->expectedPattern).unescape());
905         UDateTimePatternMatchOptions options = testDataPtr->options;
906 
907         DateTimePatternGenerator * dtpgen = DateTimePatternGenerator::createInstance(locale, status);
908         if (U_FAILURE(status)) {
909             dataerrln("Unable to create DateTimePatternGenerator instance for locale(%s): %s", locale.getName(), u_errorName(status));
910             delete dtpgen;
911             continue;
912         }
913         UnicodeString pattern = dtpgen->getBestPattern(skel, options, status);
914         if (pattern.compare(expectedPattern) != 0) {
915             errln( UnicodeString("ERROR in getBestPattern, locale ") + UnicodeString(testDataPtr->locale) +
916                    UnicodeString(", skeleton ") + skel +
917                    ((options)?UnicodeString(", options!=0"):UnicodeString(", options==0")) +
918                    UnicodeString(", expected pattern ") + expectedPattern +
919                    UnicodeString(", got ") + pattern );
920         }
921         delete dtpgen;
922     }
923 }
924 
925 /**
926  * Test that DTPG can handle all valid pattern character / length combinations
927  *
928  */
929 #define FIELD_LENGTHS_COUNT 6
930 #define FIELD_LENGTH_MAX 8
931 #define MUST_INCLUDE_COUNT 5
932 
933 typedef struct AllFieldsTestItem {
934     char patternChar;
935     int8_t fieldLengths[FIELD_LENGTHS_COUNT+1]; // up to FIELD_LENGTHS_COUNT lengths to try
936                                                 // (length <=FIELD_LENGTH_MAX) plus 0 terminator
937     char mustIncludeOneOf[MUST_INCLUDE_COUNT+1];// resulting pattern must include at least one of
938                                                 // these as a pattern char (0-terminated list)
939 } AllFieldsTestItem;
940 
testAllFieldPatterns()941 void IntlTestDateTimePatternGeneratorAPI::testAllFieldPatterns(/*char *par*/)
942 {
943     const char * localeNames[] = {
944         "root",
945         "root@calendar=japanese",
946         "root@calendar=chinese",
947         "en",
948         "en@calendar=japanese",
949         "en@calendar=chinese",
950         NULL // terminator
951     };
952     AllFieldsTestItem testData[] = {
953         //pat   fieldLengths    generated pattern must
954         //chr   to test         include one of these
955         { 'G',  {1,2,3,4,5,0},  "G"    }, // era
956         // year
957         { 'y',  {1,2,3,4,0},    "yU"   }, // year
958         { 'Y',  {1,2,3,4,0},    "Y"    }, // year for week of year
959         { 'u',  {1,2,3,4,5,0},  "yuU"  }, // extended year
960         { 'U',  {1,2,3,4,5,0},  "yU"   }, // cyclic year name
961         // quarter
962         { 'Q',  {1,2,3,4,0},    "Qq"   }, // x
963         { 'q',  {1,2,3,4,0},    "Qq"   }, // standalone
964         // month
965         { 'M',  {1,2,3,4,5,0},  "ML"   }, // x
966         { 'L',  {1,2,3,4,5,0},  "ML"   }, // standalone
967         // week
968         { 'w',  {1,2,0},        "w"    }, // week of year
969         { 'W',  {1,0},          "W"    }, // week of month
970         // day
971         { 'd',  {1,2,0},        "d"    }, // day of month
972         { 'D',  {1,2,3,0},      "D"    }, // day of year
973         { 'F',  {1,0},          "F"    }, // day of week in month
974         { 'g',  {7,0},          "g"    }, // modified julian day
975         // weekday
976         { 'E',  {1,2,3,4,5,6},  "Eec"  }, // day of week
977         { 'e',  {1,2,3,4,5,6},  "Eec"  }, // local day of week
978         { 'c',  {1,2,3,4,5,6},  "Eec"  }, // standalone local day of week
979         // day period
980         { 'a',  {1,2,3,4,5,0},  "a"    }, // am or pm
981         { 'b',  {1,2,3,4,5,0},  "b"    }, // dayPeriod AM/PM/noon
982         { 'B',  {1,2,3,4,5,0},  "B"    }, // dayPeriod ranges
983         // hour
984         { 'h',  {1,2,0},        "hK"   }, // 12 (1-12)
985         { 'H',  {1,2,0},        "Hk"   }, // 24 (0-23)
986         { 'K',  {1,2,0},        "hK"   }, // 12 (0-11)
987         { 'k',  {1,2,0},        "Hk"   }, // 24 (1-24)
988         { 'j',  {1,2,0},        "hHKk" }, // locale default
989         { 'J',  {1,2,0},        "hHKk" }, // locale default, without any dayPeriod
990         { 'C',  {1,2,0},        "hHKk" }, // locale allowed first entry, possibly with b or B
991         // minute
992         { 'm',  {1,2,0},        "m"    }, // x
993         // second & fractions
994         { 's',  {1,2,0},        "s"    }, // x
995         { 'S',  {1,2,3,4,0},    "S"    }, // fractional second
996         { 'A',  {8,0},          "A"    }, // milliseconds in day
997         // zone
998         { 'z',  {1,2,3,4,0},    "z"    }, // x
999         { 'Z',  {1,2,3,4,5,0},  "Z"    }, // x
1000         { 'O',  {1,4,0},        "O"    }, // x
1001         { 'v',  {1,4,0},        "v"    }, // x
1002         { 'V',  {1,2,3,4,0},    "V"    }, // x
1003         { 'X',  {1,2,3,4,5,0},  "X"    }, // x
1004         { 'x',  {1,2,3,4,5,0},  "x"    }, // x
1005     };
1006 
1007     const char ** localeNamesPtr = localeNames;
1008     const char * localeName;
1009     while ( (localeName = *localeNamesPtr++) != NULL) {
1010         UErrorCode status = U_ZERO_ERROR;
1011         Locale locale = Locale::createFromName(localeName);
1012         DateTimePatternGenerator * dtpg = DateTimePatternGenerator::createInstance(locale, status);
1013         if (U_SUCCESS(status)) {
1014             const AllFieldsTestItem * testDataPtr = testData;
1015             int itemCount = UPRV_LENGTHOF(testData);
1016             for (; itemCount-- > 0; ++testDataPtr) {
1017                 char skelBuf[FIELD_LENGTH_MAX];
1018                 int32_t chrIndx, lenIndx;
1019                 for (chrIndx = 0; chrIndx < FIELD_LENGTH_MAX; chrIndx++) {
1020                     skelBuf[chrIndx] = testDataPtr->patternChar;
1021                 }
1022                 for (lenIndx = 0; lenIndx < FIELD_LENGTHS_COUNT; lenIndx++) {
1023                     int32_t skelLen = testDataPtr->fieldLengths[lenIndx];
1024                     if (skelLen <= 0) {
1025                         break;
1026                     }
1027                     if (skelLen > FIELD_LENGTH_MAX) {
1028                         continue;
1029                     }
1030                     UnicodeString skeleton(skelBuf, skelLen, US_INV);
1031                     UnicodeString pattern = dtpg->getBestPattern(skeleton, status);
1032                     if (U_FAILURE(status)) {
1033                         errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d fails: %s",
1034                               locale.getName(), testDataPtr->patternChar, skelLen, u_errorName(status));
1035                     } else if (pattern.length() <= 0) {
1036                         errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d produces 0-length pattern",
1037                               locale.getName(), testDataPtr->patternChar, skelLen);
1038                     } else {
1039                         // test that resulting pattern has at least one char in mustIncludeOneOf
1040                         UnicodeString mustIncludeOneOf(testDataPtr->mustIncludeOneOf, -1, US_INV);
1041                         int32_t patIndx, patLen = pattern.length();
1042                         UBool inQuoted = FALSE;
1043                         for (patIndx = 0; patIndx < patLen; patIndx++) {
1044                             UChar c = pattern.charAt(patIndx);
1045                             if (c == 0x27) {
1046                                 inQuoted = !inQuoted;
1047                             } else if (!inQuoted && c <= 0x007A && c >= 0x0041) {
1048                                 if (mustIncludeOneOf.indexOf(c) >= 0) {
1049                                     break;
1050                                 }
1051                             }
1052                         }
1053                         if (patIndx >= patLen) {
1054                             errln(UnicodeString("DateTimePatternGenerator getBestPattern for locale ") +
1055                                     UnicodeString(locale.getName(),-1,US_INV) +
1056                                     ", skeleton " + skeleton +
1057                                     ", produces pattern without required chars: " + pattern);
1058                         }
1059 
1060                     }
1061                 }
1062             }
1063             delete dtpg;
1064         } else {
1065             dataerrln("Create DateTimePatternGenerator instance for locale(%s) fails: %s",
1066                       locale.getName(), u_errorName(status));
1067         }
1068     }
1069 }
1070 
testStaticGetSkeleton()1071 void IntlTestDateTimePatternGeneratorAPI::testStaticGetSkeleton(/*char *par*/)
1072 {
1073     // Verify that staticGetSkeleton() doesn't mangle skeletons. (Ticket #11985)
1074     static const char* const testData[] = {
1075         "jmm",
1076         "jjmm",
1077         "Jmm",
1078         "JJmm"
1079     };
1080 
1081     for (size_t i = 0; i < UPRV_LENGTHOF(testData); i++) {
1082         UErrorCode status = U_ZERO_ERROR;
1083         UnicodeString skeleton = DateTimePatternGenerator::staticGetSkeleton(testData[i], status);
1084         if (!assertSuccess("staticGetSkeleton", status)) {
1085             return;
1086         }
1087         assertEquals("Skeleton", testData[i], skeleton);
1088     }
1089 }
1090 
testC()1091 void IntlTestDateTimePatternGeneratorAPI::testC() {
1092     const char* tests[][3] = {
1093             // These may change with actual data for Bhmm/bhmm skeletons
1094             {"zh",     "Cm",      "Bh:mm"},
1095             {"zh",     "CCm",     "Bhh:mm"},
1096             {"zh",     "CCCm",    "BBBBh:mm"},
1097             {"zh",     "CCCCm",   "BBBBhh:mm"},
1098             {"zh",     "CCCCCm",  "BBBBBh:mm"},
1099             {"zh",     "CCCCCCm", "BBBBBhh:mm"},
1100             {"de",     "Cm",      "HH:mm"},
1101             {"de",     "CCm",     "HH:mm"},
1102             {"de",     "CCCm",    "HH:mm"},
1103             {"de",     "CCCCm",   "HH:mm"},
1104             {"en",     "Cm",      "h:mm a"},
1105             {"en",     "CCm",     "hh:mm a"},
1106             {"en",     "CCCm",    "h:mm aaaa"},
1107             {"en",     "CCCCm",   "hh:mm aaaa"},
1108             {"en",     "CCCCCm",  "h:mm aaaaa"},
1109             {"en",     "CCCCCCm", "hh:mm aaaaa"},
1110             {"en-BN",  "Cm",      "h:mm b"},
1111             {"gu-IN",  "Cm",      "h:mm B"},
1112             {"und-IN", "Cm",      "h:mm a"}
1113     };
1114 
1115     UErrorCode status = U_ZERO_ERROR;
1116     int32_t numTests = UPRV_LENGTHOF(tests);
1117     for (int32_t i = 0; i < numTests; ++i) {
1118         DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(Locale(tests[i][0]), status);
1119         if (gen == NULL) {
1120             dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for %s", tests[i][0]);
1121             return;
1122         }
1123         UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1124         UnicodeString pattern = gen->getBestPattern(tests[i][1], options, status);
1125         UnicodeString expectedPattern = tests[i][2];
1126 
1127         char message[100] = "\0";
1128         strcat(message, tests[i][0]);
1129         strcat(message, "/");
1130         strcat(message, tests[i][1]);
1131         assertEquals(message, expectedPattern, pattern);
1132         delete gen;
1133     }
1134 }
1135 
1136 enum { kCharBufMax = 31 };
testSkeletonsWithDayPeriods()1137 void IntlTestDateTimePatternGeneratorAPI::testSkeletonsWithDayPeriods() {
1138     const char * patterns[] = {
1139         // since icu4c getEmptyInstance does not call addCanonicalItems (unlike J), set these here:
1140         "a",    // should get internal skeleton a
1141         "H",    // should get internalskeleton H
1142         "m",    // should get internalskeleton m
1143         "s",    // should get internalskeleton s
1144         // patterns from which to construct sample data for a locale
1145         //"H",  // should get internalskeleton H
1146         "h a",  // should get internalskeleton ah
1147         "B h",  // should get internalskeleton Bh
1148     };
1149     const char* testItems[][2] = {
1150         // sample requested skeletons and results
1151         // skel     pattern
1152         { "H",      "H"},
1153         { "HH",     "HH"},
1154         { "aH",     "H"},
1155         { "aHH",    "HH"},
1156         { "BH",     "H"},
1157         { "BHH",    "HH"},
1158         { "BBBBH",  "H"},
1159         { "h",      "h a"},
1160         { "hh",     "hh a"},
1161         { "ah",     "h a"},
1162         { "ahh",    "hh a"},
1163         { "aaaah",  "h aaaa"},
1164         { "aaaahh", "hh aaaa"},
1165         { "bh",     "h b"},
1166         { "bhh",    "hh b"},
1167         { "bbbbh",  "h bbbb"},
1168         { "Bh",     "B h"},
1169         { "Bhh",    "B hh"},
1170         { "BBBBh",  "BBBB h"},
1171         { "BBBBhh", "BBBB hh"},
1172         { "a",      "a"},
1173         { "aaaaa",  "aaaaa"},
1174         { "b",      "b"},
1175         { "bbbb",   "bbbb"},
1176         { "B",      "B"},
1177         { "BBBB",  "BBBB"},
1178     };
1179     UErrorCode status = U_ZERO_ERROR;
1180     DateTimePatternGenerator *gen = DateTimePatternGenerator::createEmptyInstance(status);
1181     if (U_FAILURE(status)) {
1182         errln("ERROR: createEmptyInstance fails, status: %s", u_errorName(status));
1183     } else {
1184         int32_t i, len = UPRV_LENGTHOF(patterns);
1185         for (i = 0; i < len; i++) {
1186             UnicodeString conflictingPattern;
1187             (void)gen->addPattern(UnicodeString(patterns[i]), TRUE, conflictingPattern, status);
1188             if (U_FAILURE(status)) {
1189                 errln("ERROR: addPattern %s fail, status: %s", patterns[i], u_errorName(status));
1190                 break;
1191             }
1192         }
1193         if (U_SUCCESS(status)) {
1194             len = UPRV_LENGTHOF(testItems);
1195             for (i = 0; i < len; i++) {
1196                 status = U_ZERO_ERROR;
1197                 UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1198                 UnicodeString result = gen->getBestPattern(UnicodeString(testItems[i][0]), options, status);
1199                 if (U_FAILURE(status)) {
1200                     errln("ERROR: getBestPattern %s fail, status: %s", testItems[i][0], u_errorName(status));
1201                 } else if (result != UnicodeString(testItems[i][1])) {
1202                     char charResult[kCharBufMax+1];
1203                     result.extract(0, result.length(), charResult, kCharBufMax);
1204                     charResult[kCharBufMax] = 0; // ensure termination
1205                     errln("ERROR: getBestPattern %s, expected %s, got %s", testItems[i][0], testItems[i][1], charResult);
1206                 }
1207             }
1208         }
1209     }
1210     delete gen;
1211 }
1212 
1213 #endif /* #if !UCONFIG_NO_FORMATTING */
1214