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