• 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 "unicode/datefmt.h"
23 #include "cmemory.h"
24 #include "cstring.h"
25 #include "loctest.h"
26 
27 
28 // This is an API test, not a unit test.  It doesn't test very many cases, and doesn't
29 // try to test the full functionality.  It just calls each function in the class and
30 // verifies that it works on a basic level.
31 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)32 void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
33 {
34     if (exec) logln("TestSuite DateTimePatternGeneratorAPI");
35     switch (index) {
36         TESTCASE(0, testAPI);
37         TESTCASE(1, testOptions);
38         TESTCASE(2, testAllFieldPatterns);
39         TESTCASE(3, testStaticGetSkeleton);
40         TESTCASE(4, testC);
41         TESTCASE(5, testSkeletonsWithDayPeriods);
42         TESTCASE(6, testGetFieldDisplayNames);
43         TESTCASE(7, testJjMapping);
44         TESTCASE(8, test20640_HourCyclArsEnNH);
45         TESTCASE(9, testFallbackWithDefaultRootLocale);
46         TESTCASE(10, testGetDefaultHourCycle_OnEmptyInstance);
47         TESTCASE(11, test_jConsistencyOddLocales);
48         TESTCASE(12, testBestPattern);
49         TESTCASE(13, testDateTimePatterns);
50         TESTCASE(14, testRegionOverride);
51         default: name = ""; break;
52     }
53 }
54 
55 #define MAX_LOCALE   12
56 
57 /**
58  * Test various generic API methods of DateTimePatternGenerator for API coverage.
59  */
testAPI()60 void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
61 {
62     UnicodeString patternData[] = {
63         UnicodeString("yM"),        // 00
64         UnicodeString("yMMM"),      // 01
65         UnicodeString("yMd"),       // 02
66         UnicodeString("yMMMd"),     // 03
67         UnicodeString("Md"),        // 04
68         UnicodeString("MMMd"),      // 05
69         UnicodeString("MMMMd"),     // 06
70         UnicodeString("yQQQ"),      // 07
71         UnicodeString("hhmm"),      // 08
72         UnicodeString("HHmm"),      // 09
73         UnicodeString("jjmm"),      // 10
74         UnicodeString("mmss"),      // 11
75         UnicodeString("yyyyMMMM"),  // 12
76         UnicodeString("MMMEd"),     // 13
77         UnicodeString("Ed"),        // 14
78         UnicodeString("jmmssSSS"),  // 15
79         UnicodeString("JJmm"),      // 16
80         UnicodeString(),
81      };
82 
83     const char* testLocale[MAX_LOCALE][4] = {
84         {"en", "US", "", ""},                   // 0
85         {"en", "US", "", "calendar=japanese"},  // 1
86         {"de", "DE", "", ""},                   // 2
87         {"fi", "", "", ""},                     // 3
88         {"es", "", "", ""},                     // 4
89         {"ja", "", "", ""},                     // 5
90         {"ja", "", "", "calendar=japanese"},    // 6
91         {"zh", "Hans", "CN", ""},               // 7
92         {"zh", "TW", "", "calendar=roc"},       // 8
93         {"ru", "", "", ""},                     // 9
94         {"zh", "", "", "calendar=chinese"},     // 10
95         {"ja", "JP", "TRADITIONAL", ""},        // 11
96      };
97 
98     // For Weds, Jan 13, 1999, 23:58:59
99     UnicodeString patternResults_en_US[] = {
100         // en_US                                              // 0 en_US
101         UnicodeString("1/1999"),                              // 00: yM
102         UnicodeString("Jan 1999"),                            // 01: yMMM
103         UnicodeString("1/13/1999"),                           // 02: yMd
104         UnicodeString("Jan 13, 1999"),                        // 03: yMMMd
105         UnicodeString("1/13"),                                // 04: Md
106         UnicodeString("Jan 13"),                              // 05: MMMd
107         UnicodeString("January 13"),                          // 06: MMMMd
108         UnicodeString("Q1 1999"),                             // 07: yQQQ
109         UnicodeString(u"11:58\u202FPM", -1),                 // 08: hhmm
110         UnicodeString("23:58"),                               // 09: HHmm
111         UnicodeString(u"11:58\u202FPM", -1),                 // 10: jjmm
112         UnicodeString("58:59"),                               // 11: mmss
113         UnicodeString("January 1999"),                        // 12: yyyyMMMM
114         UnicodeString("Wed, Jan 13"),                         // 13: MMMEd -> EEE, MMM d
115         UnicodeString("13 Wed"),                              // 14: Ed    -> d EEE
116         UnicodeString(u"11:58:59.123\u202FPM", -1),          // 15: jmmssSSS -> "h:mm:ss.SSS a"
117         UnicodeString("11:58"),                               // 16: JJmm
118     };
119 
120     UnicodeString patternResults_en_US_japanese[] = {
121         // en_US@calendar=japanese                            // 1 en_US@calendar=japanese
122         UnicodeString("1/11 H"),                              //  0: yM
123         UnicodeString("Jan 11 Heisei"),                       //  1: yMMM
124         UnicodeString("1/13/11 H"),                           //  2: yMd
125         UnicodeString("Jan 13, 11 Heisei"),                   //  3: yMMMd
126         UnicodeString("1/13"),                                //  4: Md
127         UnicodeString("Jan 13"),                              //  5: MMMd
128         UnicodeString("January 13"),                          //  6: MMMMd
129         UnicodeString("Q1 11 Heisei"),                        //  7: yQQQ
130         UnicodeString(u"11:58\u202FPM", -1),                 //  8: hhmm
131         UnicodeString("23:58"),                               //  9: HHmm
132         UnicodeString(u"11:58\u202FPM", -1),                 // 10: jjmm
133         UnicodeString("58:59"),                               // 11: mmss
134         UnicodeString("January 11 Heisei"),                   // 12: yyyyMMMM
135         UnicodeString("Wed, Jan 13"),                         // 13: MMMEd -> EEE, MMM d"
136         UnicodeString("13 Wed"),                              // 14: Ed    -> d EEE
137         UnicodeString(u"11:58:59.123\u202FPM", -1),          // 15: jmmssSSS -> "h:mm:ss.SSS a"
138         UnicodeString("11:58"),                               // 16: JJmm
139     };
140 
141     UnicodeString patternResults_de_DE[] = {
142         // de_DE                                              // 2 de_DE
143         UnicodeString("01/1999"),                             // 00: yM
144         UnicodeString("Jan. 1999"),                           // 01: yMMM
145         UnicodeString("13.1.1999"),                           // 02: yMd
146         UnicodeString("13. Jan. 1999"),                       // 03: yMMMd
147         UnicodeString("13.1."),                               // 04: Md
148         UnicodeString("13. Jan."),                            // 05: MMMd
149         UnicodeString("13. Januar"),                          // 06: MMMMd
150         UnicodeString("Q1 1999"),                             // 07: yQQQ
151         UnicodeString(u"11:58\u202FPM", -1),                 // 08: hhmm
152         UnicodeString("23:58"),                               // 09: HHmm
153         UnicodeString("23:58"),                               // 10: jjmm
154         UnicodeString("58:59"),                               // 11: mmss
155         UnicodeString("Januar 1999"),                         // 12: yyyyMMMM
156         UnicodeString("Mi., 13. Jan."),                       // 13: MMMEd -> EEE, d. MMM
157         UnicodeString("Mi., 13."),                            // 14: Ed   -> EEE d.
158         UnicodeString("23:58:59,123"),                        // 15: jmmssSSS -> "HH:mm:ss,SSS"
159         UnicodeString("23:58"),                               // 16: JJmm
160     };
161 
162     UnicodeString patternResults_fi[] = {
163         // fi                                                 // 3 fi
164         UnicodeString("1.1999"),                              // 00: yM (fixed expected result per ticket:6626:)
165         UnicodeString("tammi 1999"),                          // 01: yMMM
166         UnicodeString("13.1.1999"),                           // 02: yMd
167         UnicodeString("13. tammik. 1999"),                    // 03: yMMMd
168         UnicodeString("13.1."),                               // 04: Md
169         UnicodeString("13. tammik."),                         // 05: MMMd
170         UnicodeString("13. tammikuuta"),                      // 06: MMMMd
171         UnicodeString("1. nelj. 1999"),                       // 07: yQQQ
172         UnicodeString(u"11.58\u202Fip.", -1),                // 08: hhmm
173         UnicodeString("23.58"),                               // 09: HHmm
174         UnicodeString("23.58"),                               // 10: jjmm
175         UnicodeString("58.59"),                               // 11: mmss
176         UnicodeString("tammikuu 1999"),                       // 12: yyyyMMMM
177         UnicodeString("ke 13. tammik."),                      // 13: MMMEd -> EEE d. MMM
178         UnicodeString("ke 13."),                              // 14: Ed    -> ccc d.
179         UnicodeString("23.58.59,123"),                        // 15: jmmssSSS -> "H.mm.ss,SSS"
180         UnicodeString("23.58"),                               // 16: JJmm
181     };
182 
183     UnicodeString patternResults_es[] = {
184         // es                                                 // 4 es
185         UnicodeString("1/1999"),                              // 00: yM    -> "M/y"
186         UnicodeString("ene 1999"),                            // 01: yMMM  -> "MMM y"
187         UnicodeString("13/1/1999"),                           // 02: yMd   -> "d/M/y"
188         UnicodeString("13 ene 1999"),                         // 03: yMMMd -> "d MMM y"
189         UnicodeString("13/1"),                                // 04: Md    -> "d/M"
190         UnicodeString("13 ene"),                              // 05: MMMd  -> "d 'de' MMM"
191         UnicodeString("13 de enero"),                         // 06: MMMMd -> "d 'de' MMMM"
192         UnicodeString("T1 1999"),                             // 07: yQQQ  -> "QQQ y"
193         UnicodeString(u"11:58\u202Fp.\u00A0m.", -1),          // 08: hhmm  -> "hh:mm a"
194         UnicodeString("23:58"),                               // 09: HHmm  -> "HH:mm"
195         UnicodeString("23:58"),                               // 10: jjmm  -> "HH:mm"
196         UnicodeString("58:59"),                               // 11: mmss  -> "mm:ss"
197         UnicodeString("enero de 1999"),                       // 12: yyyyMMMM -> "MMMM 'de' yyyy"
198         CharsToUnicodeString("mi\\u00E9, 13 ene"),            // 13: MMMEd -> "E, d MMM"
199         CharsToUnicodeString("mi\\u00E9 13"),                 // 14: Ed    -> "EEE d"
200         UnicodeString("23:58:59,123"),                        // 15: jmmssSSS -> "H:mm:ss,SSS"
201         UnicodeString("23:58"),                               // 16: JJmm
202     };
203 
204     UnicodeString patternResults_ja[] = {
205         // ja                                                             // 5 ja
206         UnicodeString("1999/1"),                                          // 00: yM    -> y/M
207         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 01: yMMM  -> y\u5E74M\u6708
208         UnicodeString("1999/1/13"),                                       // 02: yMd   -> y/M/d
209         CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),             // 03: yMMMd -> y\u5E74M\u6708d\u65E5
210         UnicodeString("1/13"),                                            // 04: Md    -> M/d
211         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5
212         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
213         CharsToUnicodeString("1999/Q1"),                                  // 07: yQQQ  -> y/QQQ
214         CharsToUnicodeString("\\u5348\\u5F8C11:58"),                      // 08: hhmm
215         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm
216         UnicodeString("23:58"),                                           // 10: jjmm
217         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss
218         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 12: yyyyMMMM  -> y\u5E74M\u6708
219         CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"),               // 13: MMMEd -> M\u6708d\u65E5(EEE)
220         CharsToUnicodeString("13\\u65E5(\\u6C34)"),                       // 14: Ed    -> d\u65E5(EEE)
221         UnicodeString("23:58:59.123"),                                    // 15: jmmssSSS -> "H:mm:ss.SSS"
222         UnicodeString("23:58"),                                           // 16: JJmm
223     };
224 
225     UnicodeString patternResults_ja_japanese[] = {
226         // ja@calendar=japanese                                           // 6 ja@calendar=japanese
227         UnicodeString("H11/1"),                                           // 00: yM    -> GGGGGy/m
228         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"),          // 01: yMMM  -> Gy\u5E74M\u6708
229         UnicodeString("H11/1/13"),                                        // 02: yMd   -> GGGGGy/m/d
230         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
231         UnicodeString("1/13"),                                            // 04: Md    -> M/d
232         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5
233         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
234         CharsToUnicodeString("\\u5E73\\u621011/Q1"),                     // 07: yQQQ  -> Gy/QQQ
235         CharsToUnicodeString("\\u5348\\u5F8C11:58"),                      // 08: hhmm  ->
236         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm          (as for ja)
237         UnicodeString("23:58"),                                           // 10: jjmm
238         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss          (as for ja)
239         CharsToUnicodeString("\\u5E73\\u621011\\u5E741\\u6708"),          // 12: yyyyMMMM  -> Gyyyy\u5E74M\u6708
240         CharsToUnicodeString("1\\u670813\\u65E5(\\u6C34)"),               // 13: MMMEd -> M\u6708d\u65E5(EEE)
241         CharsToUnicodeString("13\\u65E5(\\u6C34)"),                       // 14: Ed    -> d\u65E5(EEE)
242         UnicodeString("23:58:59.123"),                                    // 15: jmmssSSS -> "H:mm:ss.SSS"
243         UnicodeString("23:58"),                                           // 16: JJmm
244     };
245 
246     UnicodeString patternResults_zh_Hans_CN[] = {
247         // zh_Hans_CN                                                     // 7 zh_Hans_CN
248         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 00: yM -> y\u5E74M\u6708
249         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 01: yMMM  -> yyyy\u5E74MMM (fixed expected result per ticket:6626:)
250         CharsToUnicodeString("1999/1/13"),                                // 02: yMd
251         CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),             // 03: yMMMd -> yyyy\u5E74MMMd\u65E5 (fixed expected result per ticket:6626:)
252         UnicodeString("1/13"),                                            // 04: Md
253         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  -> M\u6708d\u65E5 (fixed expected result per ticket:6626:)
254         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  -> M\u6708d\u65E5
255         CharsToUnicodeString("1999\\u5E74\\u7B2C1\\u5B63\\u5EA6"),        // 07: yQQQ
256         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 08: hhmm
257         UnicodeString("23:58"),                                           // 09: HHmm
258         CharsToUnicodeString("23:58"),                                    // 10: jjmm
259         UnicodeString("58:59"),                                           // 11: mmss
260         CharsToUnicodeString("1999\\u5E741\\u6708"),                      // 12: yyyyMMMM  -> yyyy\u5E74MMM
261         CharsToUnicodeString("1\\u670813\\u65E5\\u5468\\u4E09"),          // 13: MMMEd -> MMMd\u65E5EEE
262         CharsToUnicodeString("13\\u65E5\\u5468\\u4E09"),                  // 14: Ed    -> d\u65E5EEE
263         CharsToUnicodeString("23:58:59.123"),                             // 15: jmmssSSS -> "ah:mm:ss.SSS"
264         UnicodeString("23:58"),                                           // 16: JJmm
265     };
266 
267     UnicodeString patternResults_zh_TW_roc[] = {
268         // zh_TW@calendar=roc                                             // 8 zh_TW@calendar=roc
269         CharsToUnicodeString("\\u6C11\\u570B88/1"),                       // 00: yM    -> Gy/M
270         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"),          // 01: yMMM  -> Gy\u5E74M\u6708
271         CharsToUnicodeString("\\u6C11\\u570B88/1/13"),                    // 02: yMd   -> Gy/M/d
272         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u670813\\u65E5"), // 03: yMMMd -> Gy\u5E74M\u6708d\u65E5
273         UnicodeString("1/13"),                                            // 04: Md    -> M/d
274         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 05: MMMd  ->M\u6708d\u65E5
275         CharsToUnicodeString("1\\u670813\\u65E5"),                        // 06: MMMMd  ->M\u6708d\u65E5
276         CharsToUnicodeString("\\u6C11\\u570B88\\u5E74\\u7B2C1\\u5B63"),   // 07: yQQQ  -> Gy QQQ
277         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 08: hhmm  ->
278         UnicodeString("23:58"),                                           // 09: HHmm  ->
279         CharsToUnicodeString("\\u4E0B\\u534811:58"),                      // 10: jjmm
280         UnicodeString("58:59"),                                           // 11: mmss  ->
281         CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"),          // 12: yyyyMMMM  -> Gy\u5E74M\u670
282         CharsToUnicodeString("1\\u670813\\u65E5\\u9031\\u4E09"),          // 13: MMMEd -> M\u6708d\u65E5EEE
283         CharsToUnicodeString("13 \\u9031\\u4E09"),                        // 14: Ed    -> d E
284         CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"),               // 15: jmmssSSS -> "ah:mm:ss.SSS"
285         UnicodeString("11:58"),                                           // 16: JJmm
286     };
287 
288     UnicodeString patternResults_ru[] = {
289         // ru                                                             // 9 ru
290         UnicodeString("01.1999"),                                         // 00: yM    -> MM.y
291         UnicodeString(u"\u044F\u043D\u0432. 1999\u202F\u0433.", -1),      // 01: yMMM  -> LLL y
292         UnicodeString("13.01.1999"),                                      // 02: yMd   -> dd.MM.y
293         UnicodeString(u"13 \u044F\u043D\u0432. 1999\u202F\u0433.",-1),    // 03: yMMMd -> d MMM y
294         UnicodeString("13.01"),                                           // 04: Md    -> dd.MM
295         CharsToUnicodeString("13 \\u044F\\u043D\\u0432."),                // 05: MMMd  -> d MMM
296         CharsToUnicodeString("13 \\u044F\\u043D\\u0432\\u0430\\u0440\\u044F"), // 06: MMMMd  -> d MMMM
297         UnicodeString(u"1-\u0439 \u043A\u0432. 1999\u202F\u0433.",-1),    // 07: yQQQ  -> y QQQ
298         UnicodeString(u"11:58\u202FPM", -1),                              // 08: hhmm  -> hh:mm a
299         UnicodeString("23:58"),                                           // 09: HHmm  -> HH:mm
300         UnicodeString("23:58"),                                           // 10: jjmm  -> HH:mm
301         UnicodeString("58:59"),                                           // 11: mmss  -> mm:ss
302         UnicodeString(u"\u044F\u043D\u0432\u0430\u0440\u044C 1999\u202F\u0433.",-1), // 12: yyyyMMMM -> LLLL y
303         CharsToUnicodeString("\\u0441\\u0440, 13 \\u044F\\u043D\\u0432."), // 13: MMMEd -> ccc, d MMM
304         CharsToUnicodeString("\\u0441\\u0440, 13"),                       // 14: Ed    -> EEE, d
305         UnicodeString("23:58:59,123"),                                    // 15: jmmssSSS -> "H:mm:ss,SSS"
306         UnicodeString("23:58"),                                           // 16: JJmm
307     };
308 
309     UnicodeString patternResults_zh_chinese[] = {
310         // zh@calendar=chinese                                            // 10 zh@calendar=chinese
311         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 00: yMMM
312         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 01: yMMM
313         CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"),             // 02: yMMMd
314         CharsToUnicodeString("1998\\u5E74\\u5341\\u4E00\\u670826"),             // 03: yMMMd
315         UnicodeString("11-26"),                                                 // 04: Md
316         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"),                 // 05: MMMd
317         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5"),                 // 06: MMMMd
318         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u7b2c\\u56db\\u5B63\\u5EA6"),  // 07: yQQQ
319         CharsToUnicodeString("\\u4E0B\\u534811:58"),                            // 08: hhmm
320         UnicodeString("23:58"),                                                 // 09: HHmm
321         CharsToUnicodeString("23:58"),                                          // 10: jjmm
322         UnicodeString("58:59"),                                                 // 11: mmss
323         CharsToUnicodeString("1998\\u620A\\u5BC5\\u5E74\\u5341\\u4E00\\u6708"), // 12: yyyyMMMM
324         CharsToUnicodeString("\\u5341\\u4E00\\u670826\\u65E5\\u5468\\u4E09"),   // 13: MMMEd
325         CharsToUnicodeString("26\\u65E5\\u5468\\u4E09"),                        // 14: Ed    -> d\u65E5EEE
326         CharsToUnicodeString("23:58:59.123"),                                   // 15: jmmssSS
327         UnicodeString("23:58"),                                                 // 16: JJmm
328     };
329 
330     UnicodeString patternResults_ja_jp_traditional[] = {
331         // ja_JP_TRADITIONAL                 // 11 ja_JP_TRADITIONAL
332         u"AD1999/1",                         // 00: yM
333         u"西暦1999年1月",                     // 01: yMMM
334         u"1999年1月13日",                     // 02: yMd
335         u"西暦1999年1月13日",                  // 03: yMMMd
336         u"1/13",                             // 04: Md
337         u"1月13日",                           // 05: MMMd
338         u"1月13日",                           // 06: MMMMd
339         u"西暦1999/Q1",                       // 07: yQQQ
340         u"午後11:58",                         // 08: hhmm
341         u"23:58",                            // 09: HHmm
342         u"23:58",                            // 10: jjmm
343         u"58:59",                            // 11: mmss
344         u"西暦1999年1月",                     // 12: yyyyMMMM
345         u"1月13日(水)",                       // 13: MMMEd
346         u"13日(水)",                          // 14: Ed
347         u"23:58:59.123",                     // 15: jmmssSSS
348         u"23:58",                            // 16: JJmm
349     };
350 
351     UnicodeString* patternResults[] = {
352         patternResults_en_US, // 0
353         patternResults_en_US_japanese, // 1
354         patternResults_de_DE, // 2
355         patternResults_fi, // 3
356         patternResults_es, // 4
357         patternResults_ja, // 5
358         patternResults_ja_japanese, // 6
359         patternResults_zh_Hans_CN, // 7
360         patternResults_zh_TW_roc, // 8
361         patternResults_ru, // 9
362         patternResults_zh_chinese, // 10
363         patternResults_ja_jp_traditional, // 11
364     };
365 
366     UnicodeString patternTests2[] = {
367         UnicodeString("yyyyMMMdd"),
368         UnicodeString("yyyyqqqq"),
369         UnicodeString("yMMMdd"),
370         UnicodeString("EyyyyMMMdd"),
371         UnicodeString("yyyyMMdd"),
372         UnicodeString("yyyyMMM"),
373         UnicodeString("yyyyMM"),
374         UnicodeString("yyMM"),
375         UnicodeString("yMMMMMd"),
376         UnicodeString("EEEEEMMMMMd"),
377         UnicodeString("MMMd"),
378         UnicodeString("MMMdhmm"),
379         UnicodeString("EMMMdhmms"),
380         UnicodeString("MMdhmm"),
381         UnicodeString("EEEEMMMdhmms"),
382         UnicodeString("yyyyMMMddhhmmss"),
383         UnicodeString("EyyyyMMMddhhmmss"),
384         UnicodeString("hmm"),
385         UnicodeString("hhmm"),
386         UnicodeString("hhmmVVVV"),
387         UnicodeString(""),
388     };
389     UnicodeString patternResults2[] = {
390         UnicodeString("Oct 14, 1999"),
391         UnicodeString("4th quarter 1999"),
392         UnicodeString("Oct 14, 1999"),
393         UnicodeString("Thu, Oct 14, 1999"),
394         UnicodeString("10/14/1999"),
395         UnicodeString("Oct 1999"),
396         UnicodeString("10/1999"),
397         UnicodeString("10/99"),
398         UnicodeString("O 14, 1999"),
399         UnicodeString("T, O 14"),
400         UnicodeString("Oct 14"),
401         UnicodeString(u"Oct 14, 6:58\u202FAM", -1),
402         UnicodeString(u"Thu, Oct 14, 6:58:59\u202FAM", -1),
403         UnicodeString(u"10/14, 6:58\u202FAM", -1),
404         UnicodeString(u"Thursday, Oct 14, 6:58:59\u202FAM", -1),
405         UnicodeString(u"Oct 14, 1999, 6:58:59\u202FAM", -1),
406         UnicodeString(u"Thu, Oct 14, 1999, 6:58:59\u202FAM", -1),
407         UnicodeString(u"6:58\u202FAM", -1),
408         UnicodeString(u"6:58\u202FAM", -1),
409         UnicodeString(u"6:58\u202FAM GMT", -1),
410         UnicodeString(""),
411     };
412 
413     // results for getSkeletons() and getPatternForSkeleton()
414     const UnicodeString testSkeletonsResults[] = {
415         UnicodeString("HH:mm"),
416         UnicodeString("MMMMd"),
417         UnicodeString("MMMMMdd"),
418     };
419 
420     const UnicodeString testBaseSkeletonsResults[] = {
421         UnicodeString("Hm"),
422         UnicodeString("MMMMd"),
423         UnicodeString("MMMMMd"),
424     };
425 
426     const char* testGetSkeletonAndBase[][3] = {
427         // pattern       skeleton    baseSkeleton
428         { "dd-MMM",     "MMMdd",    "MMMd" },
429         { "dd/MMMM/yy", "yyMMMMdd", "yMMMMd" },
430         { "h",          "h",        "h" },
431         { "ah",         "ah",       "ah" },
432         { "aaaah",      "aaaah",    "aaaah" },
433         { "Bh",         "Bh",       "Bh" }
434     };
435 
436     UnicodeString newDecimal(" "); // space
437     UnicodeString newAppendItemName("hrs.");
438     UnicodeString newAppendItemFormat("{1} {0}");
439     UnicodeString newDateTimeFormat("{1} {0}");
440     UErrorCode status = U_ZERO_ERROR;
441     UnicodeString conflictingPattern;
442     UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
443     (void)conflictingStatus;   // Suppress set but not used warning.
444 
445     // ======= Test CreateInstance with default locale
446     logln("Testing DateTimePatternGenerator createInstance from default locale");
447 
448     DateTimePatternGenerator *instFromDefaultLocale=DateTimePatternGenerator::createInstance(status);
449     if (U_FAILURE(status)) {
450         dataerrln("ERROR: Could not create DateTimePatternGenerator (default) - exiting");
451         return;
452     }
453     else {
454         delete instFromDefaultLocale;
455     }
456 
457     // ======= Test CreateInstance with given locale
458     logln("Testing DateTimePatternGenerator createInstance from French locale");
459     status = U_ZERO_ERROR;
460     DateTimePatternGenerator *instFromLocale=DateTimePatternGenerator::createInstance(Locale::getFrench(), status);
461     if (U_FAILURE(status)) {
462         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exiting");
463         return;
464     }
465 
466     // ======= Test clone DateTimePatternGenerator
467     logln("Testing DateTimePatternGenerator::clone()");
468     status = U_ZERO_ERROR;
469 
470 
471     UnicodeString decimalSymbol = instFromLocale->getDecimal();
472     UnicodeString newDecimalSymbol = UnicodeString("*");
473     decimalSymbol = instFromLocale->getDecimal();
474     instFromLocale->setDecimal(newDecimalSymbol);
475     DateTimePatternGenerator *cloneDTPatternGen=instFromLocale->clone();
476     decimalSymbol = cloneDTPatternGen->getDecimal();
477     if (decimalSymbol != newDecimalSymbol) {
478         errln("ERROR: inconsistency is found in cloned object.");
479     }
480     if ( !(*cloneDTPatternGen == *instFromLocale) ) {
481         errln("ERROR: inconsistency is found in cloned object.");
482     }
483 
484     if ( *cloneDTPatternGen != *instFromLocale ) {
485         errln("ERROR: inconsistency is found in cloned object.");
486     }
487 
488     delete instFromLocale;
489     delete cloneDTPatternGen;
490 
491     // ======= Test simple use cases
492     logln("Testing simple use cases");
493     status = U_ZERO_ERROR;
494     Locale deLocale=Locale::getGermany();
495     UDate sampleDate=LocaleTest::date(99, 9, 13, 23, 58, 59);
496     DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(deLocale, status);
497     if (U_FAILURE(status)) {
498         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getGermany()) - exiting");
499         return;
500     }
501     UnicodeString findPattern = gen->getBestPattern(UnicodeString("MMMddHmm"), status);
502     SimpleDateFormat *format = new SimpleDateFormat(findPattern, deLocale, status);
503     if (U_FAILURE(status)) {
504         dataerrln("ERROR: Could not create SimpleDateFormat (Locale::getGermany())");
505         delete gen;
506         return;
507     }
508     TimeZone *zone = TimeZone::createTimeZone(UnicodeString("ECT"));
509     if (zone==NULL) {
510         dataerrln("ERROR: Could not create TimeZone ECT");
511         delete gen;
512         delete format;
513         return;
514     }
515     format->setTimeZone(*zone);
516     UnicodeString dateReturned, expectedResult;
517     dateReturned.remove();
518     dateReturned = format->format(sampleDate, dateReturned, status);
519     expectedResult=UnicodeString("14. Okt., 08:58", -1, US_INV);
520     if ( dateReturned != expectedResult ) {
521         errln("ERROR: Simple test in getBestPattern with Locale::getGermany()).");
522     }
523     // add new pattern
524     status = U_ZERO_ERROR;
525     conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM", -1, US_INV), true, conflictingPattern, status);
526     if (U_FAILURE(status)) {
527         errln("ERROR: Could not addPattern - d\'. von\' MMMM");
528     }
529     status = U_ZERO_ERROR;
530     UnicodeString testPattern=gen->getBestPattern(UnicodeString("MMMMdd"), status);
531     testPattern=gen->getBestPattern(UnicodeString("MMMddHmm"), status);
532     format->applyPattern(gen->getBestPattern(UnicodeString("MMMMdHmm"), status));
533     dateReturned.remove();
534     dateReturned = format->format(sampleDate, dateReturned, status);
535     expectedResult=UnicodeString("14. von Oktober um 08:58", -1, US_INV);
536     if ( dateReturned != expectedResult ) {
537         errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM   Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
538     }
539     delete format;
540 
541     // get a pattern and modify it
542     format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
543                                                                   deLocale);
544     format->setTimeZone(*zone);
545     UnicodeString pattern;
546     pattern = format->toPattern(pattern);
547     dateReturned.remove();
548     dateReturned = format->format(sampleDate, dateReturned, status);
549     expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Sommerzeit");
550     if ( dateReturned != expectedResult ) {
551         errln("ERROR: Simple test uses full date format.");
552         errln(UnicodeString(" Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
553     }
554 
555     // modify it to change the zone.
556     UnicodeString newPattern = gen->replaceFieldTypes(pattern, UnicodeString("vvvv"), status);
557     format->applyPattern(newPattern);
558     dateReturned.remove();
559     dateReturned = format->format(sampleDate, dateReturned, status);
560     expectedResult=CharsToUnicodeString("Donnerstag, 14. Oktober 1999 um 08:58:59 Mitteleurop\\u00E4ische Zeit");
561     if ( dateReturned != expectedResult ) {
562         errln("ERROR: Simple test modify the timezone!");
563         errln(UnicodeString(" Got: ")+ dateReturned + UnicodeString(" Expected: ") + expectedResult);
564     }
565 
566     // setDeciaml(), getDeciaml()
567     gen->setDecimal(newDecimal);
568     if (newDecimal != gen->getDecimal()) {
569         errln("ERROR: unexpected result from setDecimal() and getDecimal()!.\n");
570     }
571 
572     // setAppenItemName() , getAppendItemName()
573     gen->setAppendItemName(UDATPG_HOUR_FIELD, newAppendItemName);
574     if (newAppendItemName != gen->getAppendItemName(UDATPG_HOUR_FIELD)) {
575         errln("ERROR: unexpected result from setAppendItemName() and getAppendItemName()!.\n");
576     }
577 
578     // setAppenItemFormat() , getAppendItemFormat()
579     gen->setAppendItemFormat(UDATPG_HOUR_FIELD, newAppendItemFormat);
580     if (newAppendItemFormat != gen->getAppendItemFormat(UDATPG_HOUR_FIELD)) {
581         errln("ERROR: unexpected result from setAppendItemFormat() and getAppendItemFormat()!.\n");
582     }
583 
584     // setDateTimeFormat() , getDateTimeFormat()
585     gen->setDateTimeFormat(newDateTimeFormat);
586     if (newDateTimeFormat != gen->getDateTimeFormat()) {
587         errln("ERROR: unexpected result from setDateTimeFormat() and getDateTimeFormat()!.\n");
588     }
589 
590     // ======== Test getSkeleton and getBaseSkeleton
591 
592     int32_t i, count = UPRV_LENGTHOF(testGetSkeletonAndBase);
593     for (i = 0; i < count; i++) {
594         status = U_ZERO_ERROR;
595         pattern                            = UnicodeString(testGetSkeletonAndBase[i][0]);
596         UnicodeString expectedSkeleton     = UnicodeString(testGetSkeletonAndBase[i][1]);
597         UnicodeString expectedBaseSkeleton = UnicodeString(testGetSkeletonAndBase[i][2]);
598         UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
599 		if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
600 			 errln("ERROR: Unexpected result from getSkeleton().\n");
601 			 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
602 		}
603 		retSkeleton = gen->getBaseSkeleton(pattern, status);
604 		if(U_FAILURE(status) || retSkeleton !=  expectedBaseSkeleton) {
605 			 errln("ERROR: Unexpected result from getBaseSkeleton().\n");
606 			 errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
607 		}
608     }
609 
610     delete format;
611     delete zone;
612     delete gen;
613 
614     {
615         // Trac# 6104
616         status = U_ZERO_ERROR;
617         pattern = UnicodeString("YYYYMMM");
618         UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
619         Locale loc("ja");
620         UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
621         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
622         if(U_FAILURE(status)) {
623             dataerrln("ERROR: Could not create DateTimePatternGenerator");
624             return;
625         }
626         UnicodeString bPattern = patGen->getBestPattern(pattern, status);
627         UnicodeString rDate;
628         SimpleDateFormat sdf(bPattern, loc, status);
629         rDate.remove();
630         rDate = sdf.format(testDate1, rDate);
631 
632         logln(UnicodeString(" ja locale with skeleton: YYYYMMM  Best Pattern:") + bPattern);
633         logln(UnicodeString("  Formatted date:") + rDate);
634 
635         if ( expR!= rDate ) {
636             errln(UnicodeString("\nERROR: Test Japanese month hack Got: ") + rDate +
637                   UnicodeString(" Expected: ") + expR );
638         }
639 
640         delete patGen;
641     }
642     {   // Trac# 6104
643         Locale loc("zh");
644         UnicodeString expR = CharsToUnicodeString("1999\\u5E741\\u6708"); // fixed expected result per ticket:6626:
645         UDate testDate1= LocaleTest::date(99, 0, 13, 23, 58, 59);
646         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
647         if(U_FAILURE(status)) {
648             dataerrln("ERROR: Could not create DateTimePatternGenerator");
649             return;
650         }
651         UnicodeString bPattern = patGen->getBestPattern(pattern, status);
652         UnicodeString rDate;
653         SimpleDateFormat sdf(bPattern, loc, status);
654         rDate.remove();
655         rDate = sdf.format(testDate1, rDate);
656 
657         logln(UnicodeString(" zh locale with skeleton: YYYYMMM  Best Pattern:") + bPattern);
658         logln(UnicodeString("  Formatted date:") + rDate);
659         if ( expR!= rDate ) {
660             errln(UnicodeString("\nERROR: Test Chinese month hack Got: ") + rDate +
661                   UnicodeString(" Expected: ") + expR );
662         }
663         delete patGen;
664     }
665 
666     {
667          // Trac# 6172 duplicate time pattern
668          status = U_ZERO_ERROR;
669          pattern = UnicodeString("hmv");
670          UnicodeString expR = UnicodeString(u"h:mm\u202Fa v", -1);
671          Locale loc("en");
672          DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
673          if(U_FAILURE(status)) {
674              dataerrln("ERROR: Could not create DateTimePatternGenerator");
675              return;
676          }
677          UnicodeString bPattern = patGen->getBestPattern(pattern, status);
678          logln(UnicodeString(" en locale with skeleton: hmv  Best Pattern:") + bPattern);
679 
680          if ( expR!= bPattern ) {
681              errln(UnicodeString("\nERROR: Test EN time format Got: ") + bPattern +
682                    UnicodeString(" Expected: ") + expR );
683          }
684 
685          delete patGen;
686      }
687 
688 
689     // ======= Test various skeletons.
690     logln("Testing DateTimePatternGenerator with various skeleton");
691 
692     status = U_ZERO_ERROR;
693     int32_t localeIndex=0;
694     int32_t resultIndex=0;
695     UnicodeString resultDate;
696     UDate testDate= LocaleTest::date(99, 0, 13, 23, 58, 59) + 123.0;
697     while (localeIndex < MAX_LOCALE )
698     {
699         resultIndex=0;
700         int32_t dataIndex=0;
701         UnicodeString bestPattern;
702 
703         Locale loc(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
704         logln("\n\n Locale: %s_%s_%s@%s", testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]);
705         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
706         if(U_FAILURE(status)) {
707             dataerrln("ERROR: Could not create DateTimePatternGenerator with locale index:%d . - exiting\n", localeIndex);
708             return;
709         }
710         while (patternData[dataIndex].length() > 0) {
711             log(patternData[dataIndex]);
712             bestPattern = patGen->getBestPattern(patternData[dataIndex++], status);
713             logln(UnicodeString(" -> ") + bestPattern);
714 
715             SimpleDateFormat sdf(bestPattern, loc, status);
716             resultDate.remove();
717             resultDate = sdf.format(testDate, resultDate);
718             if ( resultDate != patternResults[localeIndex][resultIndex] ) {
719                 auto* calendar = sdf.getCalendar();
720                 errln(UnicodeString("\nERROR: Test various skeletons[") + (dataIndex-1) + UnicodeString("], localeIndex ") + localeIndex +
721                       u". Got: \"" + resultDate +
722                       u"\" with calendar " + calendar->getType() +
723                       u" Expected: \"" + patternResults[localeIndex][resultIndex] + u"\"");
724             }
725 
726             resultIndex++;
727         }
728         delete patGen;
729         localeIndex++;
730     }
731 
732     // ======= More tests ticket#6110
733     logln("Testing DateTimePatternGenerator with various skeleton");
734 
735     status = U_ZERO_ERROR;
736     localeIndex=0;
737     resultIndex=0;
738     testDate= LocaleTest::date(99, 9, 13, 23, 58, 59);
739     {
740         int32_t dataIndex=0;
741         UnicodeString bestPattern;
742         logln("\n\n Test various skeletons for English locale...");
743         DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(Locale::getEnglish(), status);
744         if(U_FAILURE(status)) {
745             dataerrln("ERROR: Could not create DateTimePatternGenerator with locale English . - exiting\n");
746             return;
747         }
748         TimeZone *enZone = TimeZone::createTimeZone(UnicodeString("ECT/GMT"));
749         if (enZone==NULL) {
750             dataerrln("ERROR: Could not create TimeZone ECT");
751             delete patGen;
752             return;
753         }
754         SimpleDateFormat *enFormat = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull,
755                          DateFormat::kFull, Locale::getEnglish());
756         enFormat->setTimeZone(*enZone);
757         while (patternTests2[dataIndex].length() > 0) {
758             logln(patternTests2[dataIndex]);
759             bestPattern = patGen->getBestPattern(patternTests2[dataIndex], status);
760             logln(UnicodeString(" -> ") + bestPattern);
761             enFormat->applyPattern(bestPattern);
762             resultDate.remove();
763             resultDate = enFormat->format(testDate, resultDate);
764             if ( resultDate != patternResults2[resultIndex] ) {
765                 errln(UnicodeString("\nERROR: Test various skeletons[") + dataIndex
766                     + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") +
767                     patternResults2[resultIndex] );
768             }
769             dataIndex++;
770             resultIndex++;
771         }
772         delete patGen;
773         delete enZone;
774         delete enFormat;
775     }
776 
777 
778 
779     // ======= Test random skeleton
780     DateTimePatternGenerator *randDTGen= DateTimePatternGenerator::createInstance(status);
781     if (U_FAILURE(status)) {
782         dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exiting");
783         return;
784     }
785     UChar newChar;
786     for (i=0; i<10; ++i) {
787         UnicodeString randomSkeleton;
788         int32_t len = rand() % 20;
789         for (int32_t j=0; j<len; ++j ) {
790             while ((newChar = (UChar)(rand()%0x7f))>=(UChar)0x20) {
791                 randomSkeleton += newChar;
792             }
793         }
794         UnicodeString bestPattern = randDTGen->getBestPattern(randomSkeleton, status);
795     }
796     delete randDTGen;
797 
798     // UnicodeString randomString=Unicode
799     // ======= Test getStaticClassID()
800 
801     logln("Testing getStaticClassID()");
802     status = U_ZERO_ERROR;
803     DateTimePatternGenerator *test= DateTimePatternGenerator::createInstance(status);
804 
805     if(test->getDynamicClassID() != DateTimePatternGenerator::getStaticClassID()) {
806         errln("ERROR: getDynamicClassID() didn't return the expected value");
807     }
808     delete test;
809 
810     // ====== Test createEmptyInstance()
811 
812     logln("Testing createEmptyInstance()");
813     status = U_ZERO_ERROR;
814 
815     test = DateTimePatternGenerator::createEmptyInstance(status);
816     if(U_FAILURE(status)) {
817          errln("ERROR: Fail to create an empty instance ! - exiting.\n");
818          delete test;
819          return;
820     }
821 
822     conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status);
823     status = U_ZERO_ERROR;
824     testPattern=test->getBestPattern(UnicodeString("MMMMdd"), status);
825     conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status);
826     conflictingStatus = test->addPattern(UnicodeString("MMMMMdd"), true, conflictingPattern, status); //duplicate pattern
827     StringEnumeration *output=NULL;
828     output = test->getRedundants(status);
829     expectedResult=UnicodeString("MMMMd");
830     if (output != NULL) {
831         output->reset(status);
832         const UnicodeString *dupPattern=output->snext(status);
833         if ( (dupPattern==NULL) || (*dupPattern != expectedResult) ) {
834             errln("ERROR: Fail in getRedundants !\n");
835         }
836     }
837 
838     // ======== Test getSkeletons and getBaseSkeletons
839     StringEnumeration* ptrSkeletonEnum = test->getSkeletons(status);
840     if(U_FAILURE(status)) {
841         errln("ERROR: Fail to get skeletons !\n");
842     }
843     UnicodeString returnPattern, *ptrSkeleton;
844     ptrSkeletonEnum->reset(status);
845     count=ptrSkeletonEnum->count(status);
846     for (i=0; i<count; ++i) {
847         ptrSkeleton = (UnicodeString *)ptrSkeletonEnum->snext(status);
848         returnPattern = test->getPatternForSkeleton(*ptrSkeleton);
849         if ( returnPattern != testSkeletonsResults[i] ) {
850             errln(UnicodeString("ERROR: Unexpected result from getSkeletons and getPatternForSkeleton\nGot: ") + returnPattern
851                + UnicodeString("\nExpected: ") + testSkeletonsResults[i]
852                + UnicodeString("\n"));
853         }
854     }
855     StringEnumeration* ptrBaseSkeletonEnum = test->getBaseSkeletons(status);
856     if(U_FAILURE(status)) {
857         errln("ERROR: Fail to get base skeletons !\n");
858     }
859     count=ptrBaseSkeletonEnum->count(status);
860     for (i=0; i<count; ++i) {
861         ptrSkeleton = (UnicodeString *)ptrBaseSkeletonEnum->snext(status);
862         if ( *ptrSkeleton != testBaseSkeletonsResults[i] ) {
863             errln("ERROR: Unexpected result from getBaseSkeletons() !\n");
864         }
865     }
866 
867     // ========= DateTimePatternGenerator sample code in Userguide
868     // set up the generator
869     Locale locale = Locale::getFrench();
870     status = U_ZERO_ERROR;
871     DateTimePatternGenerator *generator = DateTimePatternGenerator::createInstance( locale, status);
872 
873     // get a pattern for an abbreviated month and day
874     pattern = generator->getBestPattern(UnicodeString("MMMd"), status);
875     SimpleDateFormat formatter(pattern, locale, status);
876 
877     zone = TimeZone::createTimeZone(UnicodeString("GMT"));
878     formatter.setTimeZone(*zone);
879     // use it to format (or parse)
880     UnicodeString formatted;
881     formatted = formatter.format(Calendar::getNow(), formatted, status);
882     // for French, the result is "13 sept."
883     formatted.remove();
884     // cannot use the result from getNow() because the value change evreyday.
885     testDate= LocaleTest::date(99, 0, 13, 23, 58, 59);
886     formatted = formatter.format(testDate, formatted, status);
887     expectedResult=UnicodeString("14 janv.");
888     if ( formatted != expectedResult ) {
889         errln("ERROR: Userguide sample code result!");
890         errln(UnicodeString(" Got: ")+ formatted + UnicodeString(" Expected: ") + expectedResult);
891     }
892 
893     delete zone;
894     delete output;
895     delete ptrSkeletonEnum;
896     delete ptrBaseSkeletonEnum;
897     delete test;
898     delete generator;
899 }
900 
901 /**
902  * Test handling of options
903  *
904  * For reference, as of ICU 4.3.3,
905  *  root/gregorian has
906  *      Hm{"H:mm"}
907  *      Hms{"H:mm:ss"}
908  *      hm{"h:mm a"}
909  *      hms{"h:mm:ss a"}
910  *  en/gregorian has
911  *      Hm{"H:mm"}
912  *      Hms{"H:mm:ss"}
913  *      hm{"h:mm a"}
914  *  be/gregorian has
915  *      HHmmss{"HH.mm.ss"}
916  *      Hm{"HH.mm"}
917  *      hm{"h.mm a"}
918  *      hms{"h.mm.ss a"}
919  */
920 typedef struct DTPtnGenOptionsData {
921     const char *locale;
922     const char *skel;
923     const UChar *expectedPattern;
924     UDateTimePatternMatchOptions    options;
925 } DTPtnGenOptionsData;
testOptions()926 void IntlTestDateTimePatternGeneratorAPI::testOptions(/*char *par*/)
927 {
928     DTPtnGenOptionsData testData[] = {
929     //   locale  skel   expectedPattern  options
930         { "en", "Hmm",  u"HH:mm",        UDATPG_MATCH_NO_OPTIONS        },
931         { "en", "HHmm", u"HH:mm",        UDATPG_MATCH_NO_OPTIONS        },
932         { "en", "hhmm", u"h:mm\u202Fa",  UDATPG_MATCH_NO_OPTIONS        },
933         { "en", "Hmm",  u"HH:mm",        UDATPG_MATCH_HOUR_FIELD_LENGTH },
934         { "en", "HHmm", u"HH:mm",        UDATPG_MATCH_HOUR_FIELD_LENGTH },
935         { "en", "hhmm", u"hh:mm\u202Fa", UDATPG_MATCH_HOUR_FIELD_LENGTH },
936         { "da", "Hmm",  u"HH.mm",        UDATPG_MATCH_NO_OPTIONS        },
937         { "da", "HHmm", u"HH.mm",        UDATPG_MATCH_NO_OPTIONS        },
938         { "da", "hhmm", u"h.mm\u202Fa",  UDATPG_MATCH_NO_OPTIONS        },
939         { "da", "Hmm",  u"H.mm",         UDATPG_MATCH_HOUR_FIELD_LENGTH },
940         { "da", "HHmm", u"HH.mm",        UDATPG_MATCH_HOUR_FIELD_LENGTH },
941         { "da", "hhmm", u"hh.mm\u202Fa", UDATPG_MATCH_HOUR_FIELD_LENGTH },
942         //
943         { "en",                   "yyyy",  u"yyyy",  UDATPG_MATCH_NO_OPTIONS },
944         { "en",                   "YYYY",  u"YYYY",  UDATPG_MATCH_NO_OPTIONS },
945         { "en",                   "U",     u"y",     UDATPG_MATCH_NO_OPTIONS },
946         { "en@calendar=japanese", "yyyy",  u"y G",   UDATPG_MATCH_NO_OPTIONS },
947         { "en@calendar=japanese", "YYYY",  u"Y G",   UDATPG_MATCH_NO_OPTIONS },
948         { "en@calendar=japanese", "U",     u"y G",   UDATPG_MATCH_NO_OPTIONS },
949         { "en@calendar=chinese",  "yyyy",  u"r(U)",  UDATPG_MATCH_NO_OPTIONS },
950         { "en@calendar=chinese",  "YYYY",  u"Y(Y)",  UDATPG_MATCH_NO_OPTIONS }, // not a good result, want r(Y) or r(U)
951         { "en@calendar=chinese",  "U",     u"r(U)",   UDATPG_MATCH_NO_OPTIONS },
952         { "en@calendar=chinese",  "Gy",    u"r(U)",   UDATPG_MATCH_NO_OPTIONS },
953         { "en@calendar=chinese",  "GU",    u"r(U)",   UDATPG_MATCH_NO_OPTIONS },
954         { "en@calendar=chinese",  "ULLL",  u"MMM U",  UDATPG_MATCH_NO_OPTIONS },
955         { "en@calendar=chinese",  "yMMM",  u"MMM r",  UDATPG_MATCH_NO_OPTIONS },
956         { "en@calendar=chinese",  "GUMMM", u"MMM r",  UDATPG_MATCH_NO_OPTIONS },
957         { "zh@calendar=chinese",  "yyyy",  u"rU年",    UDATPG_MATCH_NO_OPTIONS },
958         { "zh@calendar=chinese",  "YYYY",  u"YY年",    UDATPG_MATCH_NO_OPTIONS }, // not a good result, may want r(Y) or r(U)
959         { "zh@calendar=chinese",  "U",     u"rU年",    UDATPG_MATCH_NO_OPTIONS },
960         { "zh@calendar=chinese",  "Gy",    u"rU年",    UDATPG_MATCH_NO_OPTIONS },
961         { "zh@calendar=chinese",  "GU",    u"rU年",    UDATPG_MATCH_NO_OPTIONS },
962         { "zh@calendar=chinese",  "ULLL",  u"U年MMM",  UDATPG_MATCH_NO_OPTIONS },
963         { "zh@calendar=chinese",  "yMMM",  u"rU年MMM", UDATPG_MATCH_NO_OPTIONS },
964         { "zh@calendar=chinese",  "GUMMM", u"rU年MMM", UDATPG_MATCH_NO_OPTIONS },
965     };
966 
967     int count = UPRV_LENGTHOF(testData);
968     const DTPtnGenOptionsData * testDataPtr = testData;
969 
970     for (; count-- > 0; ++testDataPtr) {
971         UErrorCode status = U_ZERO_ERROR;
972 
973         Locale locale(testDataPtr->locale);
974         UnicodeString skel(testDataPtr->skel);
975         UnicodeString expectedPattern(testDataPtr->expectedPattern, -1);
976         UDateTimePatternMatchOptions options = testDataPtr->options;
977 
978         DateTimePatternGenerator * dtpgen = DateTimePatternGenerator::createInstance(locale, status);
979         if (U_FAILURE(status)) {
980             dataerrln("Unable to create DateTimePatternGenerator instance for locale(%s): %s", locale.getName(), u_errorName(status));
981             delete dtpgen;
982             continue;
983         }
984         UnicodeString pattern = dtpgen->getBestPattern(skel, options, status);
985         if (pattern.compare(expectedPattern) != 0) {
986             errln( UnicodeString("ERROR in getBestPattern, locale ") + UnicodeString(testDataPtr->locale) +
987                    UnicodeString(", skeleton ") + skel +
988                    ((options)?UnicodeString(", options!=0"):UnicodeString(", options==0")) +
989                    UnicodeString(", expected pattern ") + expectedPattern +
990                    UnicodeString(", got ") + pattern );
991         }
992         delete dtpgen;
993     }
994 }
995 
996 /**
997  * Test that DTPG can handle all valid pattern character / length combinations
998  *
999  */
1000 #define FIELD_LENGTHS_COUNT 6
1001 #define FIELD_LENGTH_MAX 8
1002 #define MUST_INCLUDE_COUNT 5
1003 
1004 typedef struct AllFieldsTestItem {
1005     char patternChar;
1006     int8_t fieldLengths[FIELD_LENGTHS_COUNT+1]; // up to FIELD_LENGTHS_COUNT lengths to try
1007                                                 // (length <=FIELD_LENGTH_MAX) plus 0 terminator
1008     char mustIncludeOneOf[MUST_INCLUDE_COUNT+1];// resulting pattern must include at least one of
1009                                                 // these as a pattern char (0-terminated list)
1010 } AllFieldsTestItem;
1011 
testAllFieldPatterns()1012 void IntlTestDateTimePatternGeneratorAPI::testAllFieldPatterns(/*char *par*/)
1013 {
1014     const char * localeNames[] = {
1015         "root",
1016         "root@calendar=japanese",
1017         "root@calendar=chinese",
1018         "en",
1019         "en@calendar=japanese",
1020         "en@calendar=chinese",
1021         NULL // terminator
1022     };
1023     AllFieldsTestItem testData[] = {
1024         //pat   fieldLengths    generated pattern must
1025         //chr   to test         include one of these
1026         { 'G',  {1,2,3,4,5,0},  "G"    }, // era
1027         // year
1028         { 'y',  {1,2,3,4,0},    "yU"   }, // year
1029         { 'Y',  {1,2,3,4,0},    "Y"    }, // year for week of year
1030         { 'u',  {1,2,3,4,5,0},  "yuU"  }, // extended year
1031         { 'U',  {1,2,3,4,5,0},  "yU"   }, // cyclic year name
1032         // quarter
1033         { 'Q',  {1,2,3,4,0},    "Qq"   }, // x
1034         { 'q',  {1,2,3,4,0},    "Qq"   }, // standalone
1035         // month
1036         { 'M',  {1,2,3,4,5,0},  "ML"   }, // x
1037         { 'L',  {1,2,3,4,5,0},  "ML"   }, // standalone
1038         // week
1039         { 'w',  {1,2,0},        "w"    }, // week of year
1040         { 'W',  {1,0},          "W"    }, // week of month
1041         // day
1042         { 'd',  {1,2,0},        "d"    }, // day of month
1043         { 'D',  {1,2,3,0},      "D"    }, // day of year
1044         { 'F',  {1,0},          "F"    }, // day of week in month
1045         { 'g',  {7,0},          "g"    }, // modified julian day
1046         // weekday
1047         { 'E',  {1,2,3,4,5,6},  "Eec"  }, // day of week
1048         { 'e',  {1,2,3,4,5,6},  "Eec"  }, // local day of week
1049         { 'c',  {1,2,3,4,5,6},  "Eec"  }, // standalone local day of week
1050         // day period
1051         { 'a',  {1,2,3,4,5,0},  "a"    }, // am or pm
1052         { 'b',  {1,2,3,4,5,0},  "b"    }, // dayPeriod AM/PM/noon
1053         { 'B',  {1,2,3,4,5,0},  "B"    }, // dayPeriod ranges
1054         // hour
1055         { 'h',  {1,2,0},        "hK"   }, // 12 (1-12)
1056         { 'H',  {1,2,0},        "Hk"   }, // 24 (0-23)
1057         { 'K',  {1,2,0},        "hK"   }, // 12 (0-11)
1058         { 'k',  {1,2,0},        "Hk"   }, // 24 (1-24)
1059         { 'j',  {1,2,0},        "hHKk" }, // locale default
1060         { 'J',  {1,2,0},        "hHKk" }, // locale default, without any dayPeriod
1061         { 'C',  {1,2,0},        "hHKk" }, // locale allowed first entry, possibly with b or B
1062         // minute
1063         { 'm',  {1,2,0},        "m"    }, // x
1064         // second & fractions
1065         { 's',  {1,2,0},        "s"    }, // x
1066         { 'S',  {1,2,3,4,0},    "S"    }, // fractional second
1067         { 'A',  {8,0},          "A"    }, // milliseconds in day
1068         // zone
1069         { 'z',  {1,2,3,4,0},    "z"    }, // x
1070         { 'Z',  {1,2,3,4,5,0},  "Z"    }, // x
1071         { 'O',  {1,4,0},        "O"    }, // x
1072         { 'v',  {1,4,0},        "v"    }, // x
1073         { 'V',  {1,2,3,4,0},    "V"    }, // x
1074         { 'X',  {1,2,3,4,5,0},  "X"    }, // x
1075         { 'x',  {1,2,3,4,5,0},  "x"    }, // x
1076     };
1077 
1078     const char ** localeNamesPtr = localeNames;
1079     const char * localeName;
1080     while ( (localeName = *localeNamesPtr++) != NULL) {
1081         UErrorCode status = U_ZERO_ERROR;
1082         Locale locale = Locale::createFromName(localeName);
1083         DateTimePatternGenerator * dtpg = DateTimePatternGenerator::createInstance(locale, status);
1084         if (U_SUCCESS(status)) {
1085             const AllFieldsTestItem * testDataPtr = testData;
1086             int itemCount = UPRV_LENGTHOF(testData);
1087             for (; itemCount-- > 0; ++testDataPtr) {
1088                 char skelBuf[FIELD_LENGTH_MAX];
1089                 int32_t chrIndx, lenIndx;
1090                 for (chrIndx = 0; chrIndx < FIELD_LENGTH_MAX; chrIndx++) {
1091                     skelBuf[chrIndx] = testDataPtr->patternChar;
1092                 }
1093                 for (lenIndx = 0; lenIndx < FIELD_LENGTHS_COUNT; lenIndx++) {
1094                     int32_t skelLen = testDataPtr->fieldLengths[lenIndx];
1095                     if (skelLen <= 0) {
1096                         break;
1097                     }
1098                     if (skelLen > FIELD_LENGTH_MAX) {
1099                         continue;
1100                     }
1101                     UnicodeString skeleton(skelBuf, skelLen, US_INV);
1102                     UnicodeString pattern = dtpg->getBestPattern(skeleton, status);
1103                     if (U_FAILURE(status)) {
1104                         errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d fails: %s",
1105                               locale.getName(), testDataPtr->patternChar, skelLen, u_errorName(status));
1106                     } else if (pattern.length() <= 0) {
1107                         errln("DateTimePatternGenerator getBestPattern for locale %s, skelChar %c skelLength %d produces 0-length pattern",
1108                               locale.getName(), testDataPtr->patternChar, skelLen);
1109                     } else {
1110                         // test that resulting pattern has at least one char in mustIncludeOneOf
1111                         UnicodeString mustIncludeOneOf(testDataPtr->mustIncludeOneOf, -1, US_INV);
1112                         int32_t patIndx, patLen = pattern.length();
1113                         UBool inQuoted = false;
1114                         for (patIndx = 0; patIndx < patLen; patIndx++) {
1115                             UChar c = pattern.charAt(patIndx);
1116                             if (c == 0x27) {
1117                                 inQuoted = !inQuoted;
1118                             } else if (!inQuoted && c <= 0x007A && c >= 0x0041) {
1119                                 if (mustIncludeOneOf.indexOf(c) >= 0) {
1120                                     break;
1121                                 }
1122                             }
1123                         }
1124                         if (patIndx >= patLen) {
1125                             errln(UnicodeString("DateTimePatternGenerator getBestPattern for locale ") +
1126                                     UnicodeString(locale.getName(),-1,US_INV) +
1127                                     ", skeleton " + skeleton +
1128                                     ", produces pattern without required chars: " + pattern);
1129                         }
1130 
1131                     }
1132                 }
1133             }
1134             delete dtpg;
1135         } else {
1136             dataerrln("Create DateTimePatternGenerator instance for locale(%s) fails: %s",
1137                       locale.getName(), u_errorName(status));
1138         }
1139     }
1140 }
1141 
testStaticGetSkeleton()1142 void IntlTestDateTimePatternGeneratorAPI::testStaticGetSkeleton(/*char *par*/)
1143 {
1144     // Verify that staticGetSkeleton() doesn't mangle skeletons. (Ticket #11985)
1145     static const char* const testData[] = {
1146         "jmm",
1147         "jjmm",
1148         "Jmm",
1149         "JJmm"
1150     };
1151 
1152     for (size_t i = 0; i < UPRV_LENGTHOF(testData); i++) {
1153         UErrorCode status = U_ZERO_ERROR;
1154         UnicodeString skeleton = DateTimePatternGenerator::staticGetSkeleton(testData[i], status);
1155         if (!assertSuccess("staticGetSkeleton", status)) {
1156             return;
1157         }
1158         assertEquals("Skeleton", testData[i], skeleton);
1159     }
1160 }
1161 
testC()1162 void IntlTestDateTimePatternGeneratorAPI::testC() {
1163     const char* tests[][3] = {
1164             // These may change with actual data for Bhmm/bhmm skeletons
1165             {"zh-TW",  "Cm",      "Bh:mm"},
1166             {"zh-TW",  "CCm",     "Bhh:mm"},
1167             {"zh-TW",  "CCCm",    "BBBBh:mm"},
1168             {"zh-TW",  "CCCCm",   "BBBBhh:mm"},
1169             {"zh-TW",  "CCCCCm",  "BBBBBh:mm"},
1170             {"zh-TW",  "CCCCCCm", "BBBBBhh:mm"},
1171             {"de",     "Cm",      "HH:mm"},
1172             {"de",     "CCm",     "HH:mm"},
1173             {"de",     "CCCm",    "HH:mm"},
1174             {"de",     "CCCCm",   "HH:mm"},
1175             {"en",     "Cm",      "h:mm\\u202Fa"},
1176             {"en",     "CCm",     "hh:mm\\u202Fa"},
1177             {"en",     "CCCm",    "h:mm\\u202Faaaa"},
1178             {"en",     "CCCCm",   "hh:mm\\u202Faaaa"},
1179             {"en",     "CCCCCm",  "h:mm\\u202Faaaaa"},
1180             {"en",     "CCCCCCm", "hh:mm\\u202Faaaaa"},
1181             {"en-BN",  "Cm",      "h:mm\\u202Fb"},
1182             {"gu-IN",  "Cm",      "h:mm B"},
1183             {"und-IN", "Cm",      "h:mm B"}
1184     };
1185 
1186     UErrorCode status = U_ZERO_ERROR;
1187     int32_t numTests = UPRV_LENGTHOF(tests);
1188     for (int32_t i = 0; i < numTests; ++i) {
1189         DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(
1190                 Locale::forLanguageTag(tests[i][0], status), status);
1191         if (gen == NULL) {
1192             dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for %s", tests[i][0]);
1193             return;
1194         }
1195         UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1196         UnicodeString pattern = gen->getBestPattern(tests[i][1], options, status);
1197         UnicodeString expectedPattern = UnicodeString(tests[i][2]).unescape();
1198 
1199         char message[100] = "\0";
1200         strcat(message, tests[i][0]);
1201         strcat(message, "/");
1202         strcat(message, tests[i][1]);
1203         assertEquals(message, expectedPattern, pattern);
1204         delete gen;
1205     }
1206 }
1207 
1208 enum { kCharBufMax = 31 };
testSkeletonsWithDayPeriods()1209 void IntlTestDateTimePatternGeneratorAPI::testSkeletonsWithDayPeriods() {
1210     const char * patterns[] = {
1211         // since icu4c getEmptyInstance does not call addCanonicalItems (unlike J), set these here:
1212         "a",    // should get internal skeleton a
1213         "H",    // should get internalskeleton H
1214         "m",    // should get internalskeleton m
1215         "s",    // should get internalskeleton s
1216         // patterns from which to construct sample data for a locale
1217         //"H",  // should get internalskeleton H
1218         "h a",  // should get internalskeleton ah
1219         "B h",  // should get internalskeleton Bh
1220     };
1221     const char* testItems[][2] = {
1222         // sample requested skeletons and results
1223         // skel     pattern
1224         { "H",      "H"},
1225         { "HH",     "HH"},
1226         { "aH",     "H"},
1227         { "aHH",    "HH"},
1228         { "BH",     "H"},
1229         { "BHH",    "HH"},
1230         { "BBBBH",  "H"},
1231         { "h",      "h a"},
1232         { "hh",     "hh a"},
1233         { "ah",     "h a"},
1234         { "ahh",    "hh a"},
1235         { "aaaah",  "h aaaa"},
1236         { "aaaahh", "hh aaaa"},
1237         { "bh",     "h b"},
1238         { "bhh",    "hh b"},
1239         { "bbbbh",  "h bbbb"},
1240         { "Bh",     "B h"},
1241         { "Bhh",    "B hh"},
1242         { "BBBBh",  "BBBB h"},
1243         { "BBBBhh", "BBBB hh"},
1244         { "a",      "a"},
1245         { "aaaaa",  "aaaaa"},
1246         { "b",      "b"},
1247         { "bbbb",   "bbbb"},
1248         { "B",      "B"},
1249         { "BBBB",  "BBBB"},
1250     };
1251     UErrorCode status = U_ZERO_ERROR;
1252     DateTimePatternGenerator *gen = DateTimePatternGenerator::createEmptyInstance(status);
1253     if (U_FAILURE(status)) {
1254         errln("ERROR: createEmptyInstance fails, status: %s", u_errorName(status));
1255     } else {
1256         int32_t i, len = UPRV_LENGTHOF(patterns);
1257         for (i = 0; i < len; i++) {
1258             UnicodeString conflictingPattern;
1259             (void)gen->addPattern(UnicodeString(patterns[i]), true, conflictingPattern, status);
1260             if (U_FAILURE(status)) {
1261                 errln("ERROR: addPattern %s fail, status: %s", patterns[i], u_errorName(status));
1262                 break;
1263             }
1264         }
1265         if (U_SUCCESS(status)) {
1266             len = UPRV_LENGTHOF(testItems);
1267             for (i = 0; i < len; i++) {
1268                 status = U_ZERO_ERROR;
1269                 UDateTimePatternMatchOptions options = UDATPG_MATCH_HOUR_FIELD_LENGTH;
1270                 UnicodeString result = gen->getBestPattern(UnicodeString(testItems[i][0]), options, status);
1271                 if (U_FAILURE(status)) {
1272                     errln("ERROR: getBestPattern %s fail, status: %s", testItems[i][0], u_errorName(status));
1273                 } else if (result != UnicodeString(testItems[i][1])) {
1274                     char charResult[kCharBufMax+1];
1275                     result.extract(0, result.length(), charResult, kCharBufMax);
1276                     charResult[kCharBufMax] = 0; // ensure termination
1277                     errln("ERROR: getBestPattern %s, expected %s, got %s", testItems[i][0], testItems[i][1], charResult);
1278                 }
1279             }
1280         }
1281     }
1282     delete gen;
1283 }
1284 
1285 typedef struct FieldDisplayNameData {
1286     const char *            locale;
1287     UDateTimePatternField   field;
1288     UDateTimePGDisplayWidth width;
1289     const char *            expected; // can have escapes such as \\u00E0
1290 } FieldDisplayNameData;
1291 enum { kFieldDisplayNameMax = 32 };
1292 
testGetFieldDisplayNames()1293 void IntlTestDateTimePatternGeneratorAPI::testGetFieldDisplayNames() {
1294     const FieldDisplayNameData testData[] = {
1295         /*loc      field                              width               expectedName */
1296         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_WIDE,        "Quartal" },
1297         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_ABBREVIATED, "Quart." },
1298         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_NARROW,      "Q" },
1299         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE,        "weekday of the month" },
1300         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday. of mo." },
1301         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW,      "wkday. of mo." }, // fallback
1302         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE,        "weekday of the month" },
1303         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday of mo" }, // override
1304         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW,      "wkday of mo" },
1305         { "it",    UDATPG_SECOND_FIELD,               UDATPG_WIDE,        "secondo" },
1306         { "it",    UDATPG_SECOND_FIELD,               UDATPG_ABBREVIATED, "s" },
1307         { "it",    UDATPG_SECOND_FIELD,               UDATPG_NARROW,      "s" },
1308     };
1309 
1310     int count = UPRV_LENGTHOF(testData);
1311     const FieldDisplayNameData * testDataPtr = testData;
1312     for (; count-- > 0; ++testDataPtr) {
1313         UErrorCode status = U_ZERO_ERROR;
1314         Locale locale(testDataPtr->locale);
1315         DateTimePatternGenerator * dtpg = DateTimePatternGenerator::createInstance(locale, status);
1316         if (U_FAILURE(status)) {
1317             dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s", testDataPtr->locale);
1318         } else {
1319             UChar expName[kFieldDisplayNameMax+1];
1320             u_unescape(testDataPtr->expected, expName, kFieldDisplayNameMax);
1321             expName[kFieldDisplayNameMax] = 0; // ensure 0 termination
1322             UnicodeString getName = dtpg->getFieldDisplayName(testDataPtr->field, testDataPtr->width);
1323             if (getName.compare(expName, u_strlen(expName)) != 0) {
1324                 errln("ERROR: locale %s field %d width %d, expected %s\n",
1325                       testDataPtr->locale, testDataPtr->field, testDataPtr->width, testDataPtr->expected);
1326             }
1327             delete dtpg;
1328         }
1329     }
1330 }
1331 
1332 static const UChar timeCycleChars[] = { (UChar)0x0048, (UChar)0x0068, (UChar)0x004B, (UChar)0x006B, (UChar)0 };
1333 
testJjMapping()1334 void IntlTestDateTimePatternGeneratorAPI::testJjMapping() {
1335     UErrorCode status = U_ZERO_ERROR;
1336     UnicodeString jSkeleton("j");
1337     // First test that j maps correctly by region in a locale for which we do not have data.
1338     {
1339         const char* testLocaleID = "de_US"; // short patterns from fallback locale "de" have "HH"
1340         Locale testLocale(testLocaleID);
1341         LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(testLocale, status));
1342         if (U_FAILURE(status)) {
1343             dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s: %s", testLocaleID, u_errorName(status));
1344         } else {
1345             UnicodeString jPattern = dtpg->getBestPattern(jSkeleton, UDATPG_MATCH_ALL_FIELDS_LENGTH, status); // get pattern with h e.g. "h 'Uhr' a"
1346             if (U_FAILURE(status)) {
1347                 errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, pattern j: %s", testLocaleID, u_errorName(status));
1348             } else {
1349                 UnicodeString jPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(jPattern, status); // strip literals, get e.g. "ah"
1350                 if (U_FAILURE(status)) {
1351                     errln("FAIL: DateTimePatternGenerator::staticGetSkeleton locale %s: %s", testLocaleID, u_errorName(status));
1352                 } else if (jPatSkeleton.indexOf(u'h') < 0) { // expect US preferred cycle 'h', not H or other cycle
1353                     errln("ERROR: DateTimePatternGenerator::getBestPattern locale %s, pattern j did not use 'h'", testLocaleID);
1354                 }
1355             }
1356         }
1357     }
1358 
1359     // Next test that in all available Locales, the actual short time pattern uses the same cycle as produced by 'j'
1360     int32_t locCount;
1361     const Locale* localePtr = DateFormat::getAvailableLocales(locCount);
1362     for (; locCount-- > 0; localePtr++) {
1363         const char* localeID = localePtr->getName();
1364         status = U_ZERO_ERROR;
1365         LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(*localePtr, status));
1366         if (U_FAILURE(status)) {
1367             dataerrln("FAIL: DateTimePatternGenerator::createInstance failed for locale %s: %s", localeID, u_errorName(status));
1368             continue;
1369         }
1370         LocalPointer<DateFormat> dfmt(DateFormat::createTimeInstance(DateFormat::kShort, *localePtr));
1371         if (U_FAILURE(status)) {
1372             dataerrln("FAIL: DateFormat::createTimeInstance kShort failed for locale %s: %s", localeID, u_errorName(status));
1373             continue;
1374         }
1375         const SimpleDateFormat* sdfmt;
1376         if ((sdfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(dfmt.getAlias()))) == NULL) {
1377             continue;
1378         }
1379         UnicodeString shortPattern;
1380         shortPattern = sdfmt->toPattern(shortPattern);
1381         UnicodeString jPattern = dtpg->getBestPattern(jSkeleton, status);
1382         if (U_FAILURE(status)) {
1383             errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, pattern j: %s", localeID, u_errorName(status));
1384             continue;
1385         }
1386         // Now check that shortPattern and jPattern use the same hour cycle
1387         UnicodeString jPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(jPattern, status);
1388         UnicodeString shortPatSkeleton = DateTimePatternGenerator::staticGetSkeleton(shortPattern, status);
1389         if (U_FAILURE(status)) {
1390             errln("FAIL: DateTimePatternGenerator::staticGetSkeleton locale %s: %s", localeID, u_errorName(status));
1391             continue;
1392         }
1393         const UChar* charPtr = timeCycleChars;
1394         for (; *charPtr != (UChar)0; charPtr++) {
1395              if (jPatSkeleton.indexOf(*charPtr) >= 0) {
1396                  if (shortPatSkeleton.indexOf(*charPtr) < 0) {
1397                      char jcBuf[2], spBuf[32], jpBuf[32];
1398                      u_austrncpy(jcBuf, charPtr, 1);
1399                      jcBuf[1] = 0;
1400                      shortPattern.extract(0, shortPattern.length(), spBuf, 32);
1401                      jPattern.extract(0, jPattern.length(), jpBuf, 32);
1402                      const char* dfmtCalType = (dfmt->getCalendar())->getType();
1403                      const char* validLoc = dfmt->getLocaleID(ULOC_VALID_LOCALE, status);
1404                      errln("ERROR: locale %s (valid %s), expected j resolved char %s to occur in short time pattern '%s' for %s (best pattern: '%s')",
1405                              localeID, validLoc, jcBuf, spBuf, dfmtCalType, jpBuf);
1406                  }
1407                  break;
1408              }
1409         }
1410     }
1411 }
1412 
test20640_HourCyclArsEnNH()1413 void IntlTestDateTimePatternGeneratorAPI::test20640_HourCyclArsEnNH() {
1414     IcuTestErrorCode status(*this, "test20640_HourCyclArsEnNH");
1415 
1416     const struct TestCase {
1417         const char* localeName;
1418         const char16_t* expectedDtpgPattern;
1419         const char16_t* expectedTimePattern;
1420         UDateFormatHourCycle expectedDefaultHourCycle;
1421     } cases[] = {
1422         // ars is interesting because it does not have a region, but it aliases
1423         // to ar_SA, which has a region.
1424         {"ars", u"h a", u"h:mm a", UDAT_HOUR_CYCLE_12},
1425         // en_NH is interesting because NH is a deprecated region code;
1426         // formerly New Hebrides, now Vanuatu => VU => h.
1427         {"en_NH", u"h\u202Fa", u"h:mm\u202Fa", UDAT_HOUR_CYCLE_12},
1428         // ch_ZH is a typo (should be zh_CN), but we should fail gracefully.
1429         {"cn_ZH", u"HH", u"HH:mm", UDAT_HOUR_CYCLE_23 }, // Desired & now actual behavior (does this fix ICU-20653?)
1430         // a non-BCP47 locale without a country code should not fail
1431         {"ja_TRADITIONAL", u"H時", u"H:mm", UDAT_HOUR_CYCLE_23},
1432     };
1433 
1434     for (auto& cas : cases) {
1435         status.setScope(cas.localeName);
1436 
1437         Locale loc(cas.localeName);
1438         LocalPointer<DateFormat> dtf(DateFormat::createTimeInstance(DateFormat::kShort, loc), status);
1439         LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(loc, status));
1440         if (status.errIfFailureAndReset()) {
1441             return;
1442         }
1443 
1444         UnicodeString timePattern;
1445         dynamic_cast<SimpleDateFormat*>(dtf.getAlias())->toPattern(timePattern);
1446         UnicodeString dtpgPattern = dtpg->getBestPattern(u"j", status);
1447         if (status.errIfFailureAndReset()) {
1448             return;
1449         }
1450         UDateFormatHourCycle defaultHourCycle = dtpg->getDefaultHourCycle(status);
1451         if (status.errIfFailureAndReset()) {
1452             return;
1453         }
1454 
1455         assertEquals(UnicodeString("dtpgPattern ") + cas.localeName,
1456             cas.expectedDtpgPattern, dtpgPattern);
1457         assertEquals(UnicodeString("timePattern ") + cas.localeName,
1458             cas.expectedTimePattern, timePattern);
1459         assertEquals(UnicodeString("defaultHour ") + cas.localeName,
1460             cas.expectedDefaultHourCycle, defaultHourCycle);
1461     }
1462 
1463 }
1464 
testFallbackWithDefaultRootLocale()1465 void IntlTestDateTimePatternGeneratorAPI::testFallbackWithDefaultRootLocale() {
1466     UErrorCode status = U_ZERO_ERROR;
1467     char original[ULOC_FULLNAME_CAPACITY];
1468 
1469     uprv_strcpy(original, uloc_getDefault());
1470     uloc_setDefault("root", &status);
1471     if (U_FAILURE(status)) {
1472         errln("ERROR: Failed to change the default locale to root! Default is: %s\n", uloc_getDefault());
1473     }
1474 
1475     DateTimePatternGenerator* dtpg = icu::DateTimePatternGenerator::createInstance("abcdedf", status);
1476 
1477     if (U_FAILURE(status)) {
1478         errln("ERROR: expected createInstance with invalid locale to succeed. Status: %s", u_errorName(status));
1479     }
1480     if (status != U_USING_DEFAULT_WARNING) {
1481         errln("ERROR: expected createInstance to return U_USING_DEFAULT_WARNING for invalid locale and default root locale. Status: %s", u_errorName(status));
1482     }
1483 
1484     delete dtpg;
1485 
1486     uloc_setDefault(original, &status);
1487     if (U_FAILURE(status)) {
1488         errln("ERROR: Failed to change the default locale back to %s\n", original);
1489     }
1490 }
1491 
1492 // ICU-21000 Ensure that calling getDefaultHourCycle on an empty instance doesn't call UPRV_UNREACHABLE_EXIT/abort.
testGetDefaultHourCycle_OnEmptyInstance()1493 void IntlTestDateTimePatternGeneratorAPI::testGetDefaultHourCycle_OnEmptyInstance() {
1494     UErrorCode status = U_ZERO_ERROR;
1495 
1496     LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createEmptyInstance(status), status);
1497     if (U_FAILURE(status)) {
1498         errln("ERROR: createEmptyInstance failed, status: %s", u_errorName(status));
1499         return;
1500     }
1501     (void)dtpg->getDefaultHourCycle(status);
1502     if (!U_FAILURE(status)) {
1503         errln("ERROR: expected getDefaultHourCycle on an empty instance to fail, status: %s", u_errorName(status));
1504         return;
1505     }
1506 
1507     status = U_USELESS_COLLATOR_ERROR;
1508     (void)dtpg->getDefaultHourCycle(status);
1509     if (status != U_USELESS_COLLATOR_ERROR) {
1510         errln("ERROR: getDefaultHourCycle shouldn't modify status if it is already failed, status: %s", u_errorName(status));
1511         return;
1512     }
1513 }
1514 
test_jConsistencyOddLocales()1515 void IntlTestDateTimePatternGeneratorAPI::test_jConsistencyOddLocales() { // ICU-20590
1516     static const char* localeIDs[] = {
1517         "en", "ro", // known languages 12h / 24h
1518         "en-RO", "ro-US",  // known languages with known regions, hour conflict language vs region
1519         "en-XZ", "ro-XZ", // known languages 12h / 24h, unknown region
1520         "xz-RO", "xz-US",  // unknown language with known regions
1521         "xz", // unknown language
1522         "xz-ZX",  // unknown language with unknown country
1523         "ars", "wuu" // aliased locales
1524     };
1525     static const UChar* skeleton = u"jm";
1526     for (const char* localeID: localeIDs) {
1527         UErrorCode status = U_ZERO_ERROR;
1528         Locale locale(localeID);
1529         LocalPointer<DateFormat> dtfShort(DateFormat::createTimeInstance(DateFormat::kShort, locale), status);
1530         if (U_FAILURE(status)) {
1531             errln("DateFormat::createTimeInstance failed for locale %s: %s", localeID, u_errorName(status));
1532             continue;
1533         }
1534         LocalPointer<DateFormat> dtfSkel(DateFormat::createInstanceForSkeleton(skeleton, locale, status));
1535         if (U_FAILURE(status)) {
1536             errln("DateFormat::createInstanceForSkeleton failed for locale %s: %s", localeID, u_errorName(status));
1537             continue;
1538         }
1539         LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(locale, status));
1540         if (U_FAILURE(status)) {
1541             errln("DateTimePatternGenerator::createInstance failed for locale %s: %s", localeID, u_errorName(status));
1542             continue;
1543         }
1544         UnicodeString dtfShortPattern, dtfSkelPattern;
1545         dynamic_cast<SimpleDateFormat*>(dtfShort.getAlias())->toPattern(dtfShortPattern);
1546         dynamic_cast<SimpleDateFormat*>(dtfSkel.getAlias())->toPattern(dtfSkelPattern);
1547         UnicodeString dtpgPattern = (dtpg.getAlias())->getBestPattern(skeleton, status);
1548         if (U_FAILURE(status)) {
1549             errln("DateTimePatternGenerator::getBestPattern failed for locale %s: %s", localeID, u_errorName(status));
1550             continue;
1551         }
1552         if (dtfShortPattern != dtfSkelPattern || dtfSkelPattern != dtpgPattern) {
1553             const char* dtfShortValidLoc = dtfShort->getLocaleID(ULOC_VALID_LOCALE, status);
1554             const char* dtfShortActualLoc = dtfShort->getLocaleID(ULOC_ACTUAL_LOCALE, status);
1555             errln(UnicodeString("For locale ") + localeID +
1556                     " expected same pattern from DateTimePatGen: " + dtpgPattern +
1557                     ", DateFmt-forSkel: " + dtfSkelPattern + ", DateFmt-short: "  + dtfShortPattern +
1558                     "; latter has validLoc " + dtfShortValidLoc + ", actualLoc " + dtfShortActualLoc);
1559         }
1560     }
1561 }
1562 
testBestPattern()1563 void IntlTestDateTimePatternGeneratorAPI::testBestPattern() {
1564     // generic test for DateTimePatternGenerator::getBestPattern() that can be used to test multiple
1565     // bugs in the resource data
1566     const struct TestCase {
1567         const char* localeID;
1568         const char* skeleton;
1569         const UChar* expectedPattern;
1570     } testCases[] = {
1571         // ICU-21650: (See the "week day" section of https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
1572         // for a full explanation of why this is the desired behavior)
1573         // if the user asks for E, the minimum field length is 3, but if he asks for c or e, it's 1
1574         { "en_US",      "E",           u"ccc"    },
1575         { "en_US",      "c",           u"c"      },
1576         { "en_US",      "e",           u"c"      },
1577         { "en_US",      "EE",          u"ccc"    },
1578         { "en_US",      "cc",          u"cc"     },
1579         { "en_US",      "ee",          u"cc"     },
1580         { "en_US",      "EEE",         u"ccc"    },
1581         { "en_US",      "ccc",         u"ccc"    },
1582         { "en_US",      "eee",         u"ccc"    },
1583         // and if the user asked for c or e and the field length is 1 or 2, the output pattern should contain
1584         // e instead of E (e supports numeric abbreviations; E doesn't)
1585         { "en_US",      "yMEd",        u"EEE, M/d/y"         },
1586         { "en_US",      "yMcd",        u"e, M/d/y"           },
1587         { "en_US",      "yMed",        u"e, M/d/y"           },
1588         { "en_US",      "yMMEEdd",     u"EEE, MM/dd/y"       },
1589         { "en_US",      "yMMccdd",     u"ee, MM/dd/y"        },
1590         { "en_US",      "yMMeedd",     u"ee, MM/dd/y"        },
1591         { "en_US",      "yMMMEd",      u"EEE, MMM d, y"      },
1592         { "en_US",      "yMMMcccd",    u"EEE, MMM d, y"      },
1593         { "en_US",      "yMMMeeed",    u"EEE, MMM d, y"      },
1594         { "en_US",      "yMMMMEEEEd",  u"EEEE, MMMM d, y"    },
1595         { "en_US",      "yMMMMccccd",  u"EEEE, MMMM d, y"    },
1596         { "en_US",      "yMMMMeeeed",  u"EEEE, MMMM d, y"    },
1597         // ICU-21428: Bad patterns for nonstandard calendars
1598         { "en_GB",                   "yMd", u"dd/MM/y"          },
1599         { "en_GB@calendar=coptic",   "yMd", u"dd/MM/y GGGGG"    },
1600         { "en_GB@calendar=japanese", "yMd", u"dd/MM/y GGGGG"    },
1601         { "en_GB@calendar=buddhist", "yMd", u"dd/MM/y GGGGG"    },
1602         // ICU-20992: Bad patterns for missing fields
1603         { "ckb_IR",     "mmSSS",       u"mm:ss\u066bSSS"     },
1604         { "ckb_IR",     "BSSS",        u"SSS \u251c'Dayperiod': B\u2524" },
1605     };
1606 
1607     for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1608         UErrorCode err = U_ZERO_ERROR;
1609         UnicodeString actualPattern;
1610 
1611         if (uprv_strcmp(testCases[i].skeleton, "full") != 0) {
1612             LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(testCases[i].localeID, err), err);
1613             actualPattern = dtpg->getBestPattern(UnicodeString(testCases[i].skeleton), err);
1614         } else {
1615             LocalPointer<DateFormat> df(DateFormat::createDateInstance(DateFormat::kFull, testCases[i].localeID));
1616             SimpleDateFormat* sdf = dynamic_cast<SimpleDateFormat*>(df.getAlias());
1617 
1618             if (sdf != NULL) {
1619                 sdf->toPattern(actualPattern);
1620             }
1621         }
1622 
1623         if (U_FAILURE(err)) {
1624             errln("Failure for test case %s/%s: %s", testCases[i].localeID, testCases[i].skeleton, u_errorName(err));
1625         } else {
1626             char failureMessage[100];
1627             strcpy(failureMessage, "Wrong result for test case ");
1628             strcat(failureMessage, testCases[i].localeID);
1629             strcat(failureMessage, "/");
1630             strcat(failureMessage, testCases[i].skeleton);
1631             assertEquals(failureMessage, testCases[i].expectedPattern, actualPattern);
1632         }
1633     }
1634 }
1635 
testDateTimePatterns()1636 void IntlTestDateTimePatternGeneratorAPI::testDateTimePatterns() {
1637     UnicodeString skeletons[kNumDateTimePatterns] = {
1638         UnicodeString("yMMMMEEEEdjmm"), // full date, short time
1639         UnicodeString("yMMMMdjmm"),     // long date, short time
1640         UnicodeString("yMMMdjmm"),      // medium date, short time
1641         UnicodeString("yMdjmm")         // short date, short time
1642     };
1643     // The following tests some locales in which there are differences between the
1644     // DateTimePatterns of various length styles.
1645     DTPLocaleAndResults localeAndResults[] = {
1646         { "en", { UnicodeString(u"EEEE, MMMM d, y 'at' h:mm\u202Fa"), // long != medium
1647                   UnicodeString(u"MMMM d, y 'at' h:mm\u202Fa"),
1648                   UnicodeString(u"MMM d, y, h:mm\u202Fa"),
1649                   UnicodeString(u"M/d/y, h:mm\u202Fa") } },
1650         { "fr", { UnicodeString(u"EEEE d MMMM y 'à' HH:mm"), // medium != short
1651                   UnicodeString(u"d MMMM y 'à' HH:mm"),
1652                   UnicodeString(u"d MMM y, HH:mm"),
1653                   UnicodeString(u"dd/MM/y HH:mm") } },
1654         { "ha", { UnicodeString(u"EEEE d MMMM, y 'da' HH:mm"),
1655                   UnicodeString(u"d MMMM, y 'da' HH:mm"),
1656                   UnicodeString(u"d MMM, y, HH:mm"),
1657                   UnicodeString(u"y-MM-dd, HH:mm") } },
1658         { nullptr, { UnicodeString(""), UnicodeString(""), // terminator
1659                     UnicodeString(""), UnicodeString("") } },
1660     };
1661 
1662     UnicodeString enDTPatterns[kNumDateTimePatterns] = {
1663         UnicodeString(u"{1} 'at' {0}"),
1664         UnicodeString(u"{1} 'at' {0}"),
1665         UnicodeString(u"{1}, {0}"),
1666         UnicodeString(u"{1}, {0}")
1667     };
1668     UnicodeString modDTPatterns[kNumDateTimePatterns] = {
1669         UnicodeString(u"{1} _0_ {0}"),
1670         UnicodeString(u"{1} _1_ {0}"),
1671         UnicodeString(u"{1} _2_ {0}"),
1672         UnicodeString(u"{1} _3_ {0}")
1673     };
1674     DTPLocaleAndResults enModResults = { "en", { UnicodeString(u"EEEE, MMMM d, y _0_ h:mm\u202Fa"),
1675                                                  UnicodeString(u"MMMM d, y _1_ h:mm\u202Fa"),
1676                                                  UnicodeString(u"MMM d, y _2_ h:mm\u202Fa"),
1677                                                  UnicodeString(u"M/d/y _3_ h:mm\u202Fa") }
1678     };
1679 
1680     // Test various locales with standard data
1681     UErrorCode status;
1682     LocalPointer<DateTimePatternGenerator> dtpg;
1683     DTPLocaleAndResults* localeAndResultsPtr = localeAndResults;
1684     for (; localeAndResultsPtr->localeID != nullptr; localeAndResultsPtr++) {
1685         status = U_ZERO_ERROR;
1686         Locale locale(localeAndResultsPtr->localeID);
1687         dtpg.adoptInstead(DateTimePatternGenerator::createInstance(locale, status));
1688         if (U_FAILURE(status)) {
1689             dataerrln("FAIL: DateTimePatternGenerator::createInstance for locale %s: %s",
1690                         localeAndResultsPtr->localeID, u_errorName(status));
1691         } else {
1692             doDTPatternTest(dtpg.getAlias(), skeletons, localeAndResultsPtr);
1693         }
1694     }
1695     // Test getting and modifying date-time combining patterns
1696     status = U_ZERO_ERROR;
1697     dtpg.adoptInstead(DateTimePatternGenerator::createInstance(Locale::getEnglish(), status));
1698     if (U_FAILURE(status)) {
1699         dataerrln("FAIL: DateTimePatternGenerator::createInstance #2 for locale en: %s", u_errorName(status));
1700     } else {
1701         char bExpect[64];
1702         char bGet[64];
1703         // Test style out of range
1704         status = U_ZERO_ERROR;
1705         const UnicodeString& dtFormat0 = dtpg->getDateTimeFormat(UDAT_NONE, status);
1706         int32_t dtFormat0Len = dtFormat0.length();
1707         if (status != U_ILLEGAL_ARGUMENT_ERROR || dtFormat0Len != 0) {
1708             errln("ERROR: getDateTimeFormat with invalid style, expected U_ILLEGAL_ARGUMENT_ERROR and lero-length string, "
1709                   "got %s with length %d", u_errorName(status), dtFormat0Len);
1710         }
1711         // Test normal getting and setting
1712         for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
1713             status = U_ZERO_ERROR;
1714             const UnicodeString& dtFormat1 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
1715             if (U_FAILURE(status)) {
1716                 errln("FAIL: getDateTimeFormat for en before mod, style %d, get %s", patStyle, u_errorName(status));
1717             } else  if (dtFormat1 != enDTPatterns[patStyle]) {
1718                 enDTPatterns[patStyle].extract(0, enDTPatterns[patStyle].length(), bExpect, 64);
1719                 dtFormat1.extract(0, dtFormat1.length(), bGet, 64);
1720                 errln("ERROR: getDateTimeFormat for en before mod, style %d, expect \"%s\", get \"%s\"",
1721                         patStyle, bExpect, bGet);
1722             }
1723             status = U_ZERO_ERROR;
1724             dtpg->setDateTimeFormat((UDateFormatStyle)patStyle, modDTPatterns[patStyle], status);
1725             if (U_FAILURE(status)) {
1726                 errln("FAIL: setDateTimeFormat for en, style %d, get %s", patStyle, u_errorName(status));
1727             } else {
1728                 const UnicodeString& dtFormat2 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
1729                 if (U_FAILURE(status)) {
1730                     errln("FAIL: getDateTimeFormat for en after  mod, style %d, get %s", patStyle, u_errorName(status));
1731                 } else if (dtFormat2 != modDTPatterns[patStyle]) {
1732                     modDTPatterns[patStyle].extract(0, modDTPatterns[patStyle].length(), bExpect, 64);
1733                     dtFormat2.extract(0, dtFormat2.length(), bGet, 64);
1734                     errln("ERROR: getDateTimeFormat for en after mod, style %d, expect \"%s\", get \"%s\"",
1735                             patStyle, bExpect, bGet);
1736                 }
1737             }
1738         }
1739         // Test result of setting
1740         doDTPatternTest(dtpg.getAlias(), skeletons, &enModResults);
1741         // Test old get/set functions
1742         const UnicodeString& dtFormat3 = dtpg->getDateTimeFormat();
1743         if (dtFormat3 != modDTPatterns[UDAT_MEDIUM]) {
1744             modDTPatterns[UDAT_MEDIUM].extract(0, modDTPatterns[UDAT_MEDIUM].length(), bExpect, 64);
1745             dtFormat3.extract(0, dtFormat3.length(), bGet, 64);
1746             errln("ERROR: old getDateTimeFormat for en after mod, expect \"%s\", get \"%s\"", bExpect, bGet);
1747         }
1748         dtpg->setDateTimeFormat(modDTPatterns[UDAT_SHORT]); // set all dateTimePatterns to the short format
1749         modDTPatterns[UDAT_SHORT].extract(0, modDTPatterns[UDAT_SHORT].length(), bExpect, 64);
1750         for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
1751             status = U_ZERO_ERROR;
1752             const UnicodeString& dtFormat4 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status);
1753             if (U_FAILURE(status)) {
1754                 errln("FAIL: getDateTimeFormat for en after second mod, style %d, get %s", patStyle, u_errorName(status));
1755             } else if (dtFormat4 != modDTPatterns[UDAT_SHORT]) {
1756                 dtFormat4.extract(0, dtFormat4.length(), bGet, 64);
1757                 errln("ERROR: getDateTimeFormat for en after second mod, style %d, expect \"%s\", get \"%s\"",
1758                         patStyle, bExpect, bGet);
1759             }
1760         }
1761     }
1762 }
1763 
testRegionOverride()1764 void IntlTestDateTimePatternGeneratorAPI::testRegionOverride() {
1765     const struct TestCase {
1766         const char* locale;
1767         const UChar* expectedPattern;
1768         UDateFormatHourCycle expectedHourCycle;
1769     } testCases[] = {
1770         { "en_US",           u"h:mm\u202fa", UDAT_HOUR_CYCLE_12 },
1771         { "en_GB",           u"HH:mm",       UDAT_HOUR_CYCLE_23 },
1772         { "en_US@rg=GBZZZZ", u"HH:mm",       UDAT_HOUR_CYCLE_23 },
1773         { "en_US@hours=h23", u"HH:mm",       UDAT_HOUR_CYCLE_23 },
1774     };
1775 
1776     for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1777         UErrorCode err = U_ZERO_ERROR;
1778         LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(testCases[i].locale, err));
1779 
1780         if (assertSuccess("Error creating dtpg", err)) {
1781             UDateFormatHourCycle actualHourCycle = dtpg->getDefaultHourCycle(err);
1782             UnicodeString actualPattern = dtpg->getBestPattern(u"jmm", err);
1783 
1784             if (assertSuccess("Error using dtpg", err)) {
1785                 assertEquals("Wrong hour cycle", testCases[i].expectedHourCycle, actualHourCycle);
1786                 assertEquals("Wrong pattern", testCases[i].expectedPattern, actualPattern);
1787             }
1788         }
1789     }
1790 }
1791 
doDTPatternTest(DateTimePatternGenerator * dtpg,UnicodeString * skeletons,DTPLocaleAndResults * localeAndResultsPtr)1792 void IntlTestDateTimePatternGeneratorAPI::doDTPatternTest(DateTimePatternGenerator* dtpg, UnicodeString* skeletons, DTPLocaleAndResults* localeAndResultsPtr) {
1793     for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) {
1794         UErrorCode status = U_ZERO_ERROR;
1795         UnicodeString getPat = dtpg->getBestPattern(skeletons[patStyle], UDATPG_MATCH_NO_OPTIONS, status);
1796         if (U_FAILURE(status)) {
1797             errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, style %d: %s",
1798                         localeAndResultsPtr->localeID, patStyle, u_errorName(status));
1799         } else if (getPat != localeAndResultsPtr->expectPat[patStyle]) {
1800             char bExpect[64];
1801             char bGet[64];
1802             localeAndResultsPtr->expectPat[patStyle].extract(0, localeAndResultsPtr->expectPat[patStyle].length(), bExpect, 64);
1803             getPat.extract(0, getPat.length(), bGet, 64);
1804             errln("ERROR: DateTimePatternGenerator::getBestPattern locale %s, style %d, expect \"%s\", get \"%s\"",
1805                         localeAndResultsPtr->localeID, patStyle, bExpect, bGet);
1806         }
1807     }
1808 }
1809 
1810 #endif /* #if !UCONFIG_NO_FORMATTING */
1811