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