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