1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 2007-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: udatpg_test.c
12 * tab size: 8 (not used)
15 * created on: 2007aug01
16 * created by: Markus W. Scherer
18 * Test of the C wrapper for the DateTimePatternGenerator.
19 * Calls each C API function and exercises code paths in the wrapper,
20 * but the full functionality is tested in the C++ intltest.
22 * One item to note: C API functions which return a const UChar *
23 * should return a NUL-terminated string.
24 * (The C++ implementation needs to use getTerminatedBuffer()
25 * on UnicodeString objects which end up being returned this way.)
28 #include "unicode/utypes.h"
30 #if !UCONFIG_NO_FORMATTING
31 #include "unicode/udat.h"
32 #include "unicode/udatpg.h"
33 #include "unicode/ustring.h"
37 #include <stdio.h> // for sprintf()
39 void addDateTimePatternGeneratorTest(TestNode
** root
);
41 #define TESTCASE(x) addTest(root, &x, "tsformat/udatpg_test/" #x)
43 static void TestOpenClose(void);
44 static void TestUsage(void);
45 static void TestBuilder(void);
46 static void TestOptions(void);
47 static void TestGetFieldDisplayNames(void);
48 static void TestJapaneseCalendarItems(void); // rdar://52042600
49 static void TestCountryFallback(void); // rdar://problem/26911014
50 static void TestEras(void);
52 void addDateTimePatternGeneratorTest(TestNode
** root
) {
53 TESTCASE(TestOpenClose
);
55 TESTCASE(TestBuilder
);
56 TESTCASE(TestOptions
);
57 TESTCASE(TestGetFieldDisplayNames
);
58 TESTCASE(TestJapaneseCalendarItems
);
59 TESTCASE(TestCountryFallback
);
64 * Pipe symbol '|'. We pass only the first UChar without NUL-termination.
65 * The second UChar is just to verify that the API does not pick that up.
67 static const UChar pipeString
[]={ 0x7c, 0x0a };
69 static const UChar testSkeleton1
[]={ 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
70 static const UChar expectingBestPattern
[]={ 0x48, 0x2e, 0x6d, 0x6d, 0 }; /* H.mm */
71 static const UChar testPattern
[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0 }; /* HH:mm */
72 static const UChar expectingSkeleton
[]= { 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
73 static const UChar expectingBaseSkeleton
[]= { 0x48, 0x6d, 0 }; /* HHmm */
74 static const UChar redundantPattern
[]={ 0x79, 0x79, 0x4d, 0x4d, 0x4d, 0 }; /* yyMMM */
75 static const UChar testFormat
[]= {0x7B, 0x31, 0x7D, 0x20, 0x7B, 0x30, 0x7D, 0}; /* {1} {0} */
76 static const UChar appendItemName
[]= {0x68, 0x72, 0}; /* hr */
77 static const UChar testPattern2
[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x20, 0x76, 0 }; /* HH:mm v */
78 static const UChar replacedStr
[]={ 0x76, 0x76, 0x76, 0x76, 0 }; /* vvvv */
79 /* results for getBaseSkeletons() - {Hmv}, {yMMM} */
80 static const UChar resultBaseSkeletons
[2][10] = {{0x48,0x6d, 0x76, 0}, {0x79, 0x4d, 0x4d, 0x4d, 0 } };
81 static const UChar sampleFormatted
[] = {0x31, 0x30, 0x20, 0x6A, 0x75, 0x69, 0x6C, 0x2E, 0}; /* 10 juil. */
82 static const UChar skeleton
[]= {0x4d, 0x4d, 0x4d, 0x64, 0}; /* MMMd */
83 static const UChar timeZoneGMT
[] = { 0x0047, 0x004d, 0x0054, 0x0000 }; /* "GMT" */
85 static void TestOpenClose() {
86 UErrorCode errorCode
=U_ZERO_ERROR
;
87 UDateTimePatternGenerator
*dtpg
, *dtpg2
;
91 /* Open a DateTimePatternGenerator for the default locale. */
92 dtpg
=udatpg_open(NULL
, &errorCode
);
93 if(U_FAILURE(errorCode
)) {
94 log_err_status(errorCode
, "udatpg_open(NULL) failed - %s\n", u_errorName(errorCode
));
99 /* Now one for German. */
100 dtpg
=udatpg_open("de", &errorCode
);
101 if(U_FAILURE(errorCode
)) {
102 log_err("udatpg_open(de) failed - %s\n", u_errorName(errorCode
));
106 /* Make some modification which we verify gets passed on to the clone. */
107 udatpg_setDecimal(dtpg
, pipeString
, 1);
109 /* Clone the generator. */
110 dtpg2
=udatpg_clone(dtpg
, &errorCode
);
111 if(U_FAILURE(errorCode
) || dtpg2
==NULL
) {
112 log_err("udatpg_clone() failed - %s\n", u_errorName(errorCode
));
116 /* Verify that the clone has the custom decimal symbol. */
117 s
=udatpg_getDecimal(dtpg2
, &length
);
118 if(s
==pipeString
|| length
!=1 || 0!=u_memcmp(s
, pipeString
, length
) || s
[length
]!=0) {
119 log_err("udatpg_getDecimal(cloned object) did not return the expected string\n");
128 UDateTimePatternField field
;
130 } AppendItemNameData
;
132 static const AppendItemNameData appendItemNameData
[] = { /* for Finnish */
133 { UDATPG_YEAR_FIELD
, {0x0076,0x0075,0x006F,0x0073,0x0069,0} }, /* "vuosi" */
134 { UDATPG_MONTH_FIELD
, {0x006B,0x0075,0x0075,0x006B,0x0061,0x0075,0x0073,0x0069,0} }, /* "kuukausi" */
135 { UDATPG_WEEKDAY_FIELD
, {0x0076,0x0069,0x0069,0x006B,0x006F,0x006E,0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
136 { UDATPG_DAY_FIELD
, {0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
137 { UDATPG_HOUR_FIELD
, {0x0074,0x0075,0x006E,0x0074,0x0069,0} }, /* "tunti" */
138 { UDATPG_FIELD_COUNT
, {0} } /* terminator */
141 static void TestUsage() {
142 UErrorCode errorCode
=U_ZERO_ERROR
;
143 UDateTimePatternGenerator
*dtpg
;
144 const AppendItemNameData
* appItemNameDataPtr
;
145 UChar bestPattern
[20];
151 dtpg
=udatpg_open("fi", &errorCode
);
152 if(U_FAILURE(errorCode
)) {
153 log_err_status(errorCode
, "udatpg_open(fi) failed - %s\n", u_errorName(errorCode
));
156 length
= udatpg_getBestPattern(dtpg
, testSkeleton1
, 4,
157 bestPattern
, 20, &errorCode
);
158 if(U_FAILURE(errorCode
)) {
159 log_err("udatpg_getBestPattern failed - %s\n", u_errorName(errorCode
));
162 if((u_memcmp(bestPattern
, expectingBestPattern
, length
)!=0) || bestPattern
[length
]!=0) {
163 log_err("udatpg_getBestPattern did not return the expected string\n");
168 /* Test skeleton == NULL */
170 length
= udatpg_getBestPattern(dtpg
, s
, 0, bestPattern
, 20, &errorCode
);
171 if(!U_FAILURE(errorCode
)&&(length
!=0) ) {
172 log_err("udatpg_getBestPattern failed in illegal argument - skeleton is NULL.\n");
176 /* Test udatpg_getSkeleton */
177 length
= udatpg_getSkeleton(dtpg
, testPattern
, 5, result
, 20, &errorCode
);
178 if(U_FAILURE(errorCode
)) {
179 log_err("udatpg_getSkeleton failed - %s\n", u_errorName(errorCode
));
182 if((u_memcmp(result
, expectingSkeleton
, length
)!=0) || result
[length
]!=0) {
183 log_err("udatpg_getSkeleton did not return the expected string\n");
187 /* Test pattern == NULL */
189 length
= udatpg_getSkeleton(dtpg
, s
, 0, result
, 20, &errorCode
);
190 if(!U_FAILURE(errorCode
)&&(length
!=0) ) {
191 log_err("udatpg_getSkeleton failed in illegal argument - pattern is NULL.\n");
195 /* Test udatpg_getBaseSkeleton */
196 length
= udatpg_getBaseSkeleton(dtpg
, testPattern
, 5, result
, 20, &errorCode
);
197 if(U_FAILURE(errorCode
)) {
198 log_err("udatpg_getBaseSkeleton failed - %s\n", u_errorName(errorCode
));
201 if((u_memcmp(result
, expectingBaseSkeleton
, length
)!=0) || result
[length
]!=0) {
202 log_err("udatpg_getBaseSkeleton did not return the expected string\n");
206 /* Test pattern == NULL */
208 length
= udatpg_getBaseSkeleton(dtpg
, s
, 0, result
, 20, &errorCode
);
209 if(!U_FAILURE(errorCode
)&&(length
!=0) ) {
210 log_err("udatpg_getBaseSkeleton failed in illegal argument - pattern is NULL.\n");
214 /* set append format to {1}{0} */
215 udatpg_setAppendItemFormat( dtpg
, UDATPG_MONTH_FIELD
, testFormat
, 7 );
216 r
= udatpg_getAppendItemFormat(dtpg
, UDATPG_MONTH_FIELD
, &length
);
219 if(length
!=7 || 0!=u_memcmp(r
, testFormat
, length
) || r
[length
]!=0) {
220 log_err("udatpg_setAppendItemFormat did not return the expected string\n");
224 for (appItemNameDataPtr
= appendItemNameData
; appItemNameDataPtr
->field
< UDATPG_FIELD_COUNT
; appItemNameDataPtr
++) {
226 const UChar
* namePtr
= udatpg_getAppendItemName(dtpg
, appItemNameDataPtr
->field
, &nameLength
);
227 if ( namePtr
== NULL
|| u_strncmp(appItemNameDataPtr
->name
, namePtr
, nameLength
) != 0 ) {
228 log_err("udatpg_getAppendItemName returns invalid name for field %d\n", (int)appItemNameDataPtr
->field
);
232 /* set append name to hr */
233 udatpg_setAppendItemName(dtpg
, UDATPG_HOUR_FIELD
, appendItemName
, 2);
234 r
= udatpg_getAppendItemName(dtpg
, UDATPG_HOUR_FIELD
, &length
);
236 if(length
!=2 || 0!=u_memcmp(r
, appendItemName
, length
) || r
[length
]!=0) {
237 log_err("udatpg_setAppendItemName did not return the expected string\n");
241 /* set date time format to {1}{0} */
242 udatpg_setDateTimeFormat( dtpg
, testFormat
, 7 );
243 r
= udatpg_getDateTimeFormat(dtpg
, &length
);
245 if(length
!=7 || 0!=u_memcmp(r
, testFormat
, length
) || r
[length
]!=0) {
246 log_err("udatpg_setDateTimeFormat did not return the expected string\n");
252 static void TestBuilder() {
253 UErrorCode errorCode
=U_ZERO_ERROR
;
254 UDateTimePatternGenerator
*dtpg
;
255 UDateTimePatternConflict conflict
;
258 int32_t length
, pLength
;
260 const UChar
* ptrResult
[2];
262 UDateTimePatternGenerator
*generator
;
263 int32_t formattedCapacity
, resultLen
,patternCapacity
;
264 UChar pattern
[40], formatted
[40];
265 UDateFormat
*formatter
;
266 UDate sampleDate
= 837039928046.0;
267 static const char locale
[]= "fr";
268 UErrorCode status
=U_ZERO_ERROR
;
270 /* test create an empty DateTimePatternGenerator */
271 dtpg
=udatpg_openEmpty(&errorCode
);
272 if(U_FAILURE(errorCode
)) {
273 log_err("udatpg_openEmpty() failed - %s\n", u_errorName(errorCode
));
278 conflict
= udatpg_addPattern(dtpg
, redundantPattern
, 5, FALSE
, result
, 20,
279 &length
, &errorCode
);
280 if(U_FAILURE(errorCode
)) {
281 log_err("udatpg_addPattern() failed - %s\n", u_errorName(errorCode
));
284 /* Add a redundant pattern */
285 conflict
= udatpg_addPattern(dtpg
, redundantPattern
, 5, FALSE
, result
, 20,
286 &length
, &errorCode
);
287 if(conflict
== UDATPG_NO_CONFLICT
) {
288 log_err("udatpg_addPattern() failed to find the duplicate pattern.\n");
291 /* Test pattern == NULL */
293 length
= udatpg_addPattern(dtpg
, s
, 0, FALSE
, result
, 20,
294 &length
, &errorCode
);
295 if(!U_FAILURE(errorCode
)&&(length
!=0) ) {
296 log_err("udatpg_addPattern failed in illegal argument - pattern is NULL.\n");
300 /* replace field type */
301 errorCode
=U_ZERO_ERROR
;
302 conflict
= udatpg_addPattern(dtpg
, testPattern2
, 7, FALSE
, result
, 20,
303 &length
, &errorCode
);
304 if((conflict
!= UDATPG_NO_CONFLICT
)||U_FAILURE(errorCode
)) {
305 log_err("udatpg_addPattern() failed to add HH:mm v. - %s\n", u_errorName(errorCode
));
308 length
= udatpg_replaceFieldTypes(dtpg
, testPattern2
, 7, replacedStr
, 4,
309 result
, 20, &errorCode
);
310 if (U_FAILURE(errorCode
) || (length
==0) ) {
311 log_err("udatpg_replaceFieldTypes failed!\n");
315 /* Get all skeletons and the crroespong pattern for each skeleton. */
316 ptrResult
[0] = testPattern2
;
317 ptrResult
[1] = redundantPattern
;
319 en
= udatpg_openSkeletons(dtpg
, &errorCode
);
320 if (U_FAILURE(errorCode
) || (length
==0) ) {
321 log_err("udatpg_openSkeletons failed!\n");
324 while ( (s
=uenum_unext(en
, &length
, &errorCode
))!= NULL
) {
325 p
= udatpg_getPatternForSkeleton(dtpg
, s
, length
, &pLength
);
326 if (U_FAILURE(errorCode
) || p
==NULL
|| u_memcmp(p
, ptrResult
[count
], pLength
)!=0 ) {
327 log_err("udatpg_getPatternForSkeleton failed!\n");
334 /* Get all baseSkeletons */
335 en
= udatpg_openBaseSkeletons(dtpg
, &errorCode
);
337 while ( (s
=uenum_unext(en
, &length
, &errorCode
))!= NULL
) {
338 p
= udatpg_getPatternForSkeleton(dtpg
, s
, length
, &pLength
);
339 if (U_FAILURE(errorCode
) || p
==NULL
|| u_memcmp(p
, resultBaseSkeletons
[count
], pLength
)!=0 ) {
340 log_err("udatpg_getPatternForSkeleton failed!\n");
345 if (U_FAILURE(errorCode
) || (length
==0) ) {
346 log_err("udatpg_openSkeletons failed!\n");
353 /* sample code in Userguide */
354 patternCapacity
= UPRV_LENGTHOF(pattern
);
356 generator
=udatpg_open(locale
, &status
);
357 if(U_FAILURE(status
)) {
361 /* get a pattern for an abbreviated month and day */
362 length
= udatpg_getBestPattern(generator
, skeleton
, 4,
363 pattern
, patternCapacity
, &status
);
364 formatter
= udat_open(UDAT_PATTERN
, UDAT_PATTERN
, locale
, timeZoneGMT
, -1,
365 pattern
, length
, &status
);
366 if (formatter
==NULL
) {
367 log_err("Failed to initialize the UDateFormat of the sample code in Userguide.\n");
368 udatpg_close(generator
);
372 /* use it to format (or parse) */
373 formattedCapacity
= UPRV_LENGTHOF(formatted
);
374 resultLen
=udat_format(formatter
, ucal_getNow(), formatted
, formattedCapacity
,
376 /* for French, the result is "13 sept." */
378 /* cannot use the result from ucal_getNow() because the value change evreyday. */
379 resultLen
=udat_format(formatter
, sampleDate
, formatted
, formattedCapacity
,
381 if ( u_memcmp(sampleFormatted
, formatted
, resultLen
) != 0 ) {
382 log_err("Failed udat_format() of sample code in Userguide.\n");
384 udatpg_close(generator
);
385 udat_close(formatter
);
388 typedef struct DTPtnGenOptionsData
{
391 UDateTimePatternMatchOptions options
;
392 const UChar
* expectedPattern
;
393 } DTPtnGenOptionsData
;
394 enum { kTestOptionsPatLenMax
= 32 };
396 static const UChar skel_Hmm
[] = { 0x0048, 0x006D, 0x006D, 0 };
397 static const UChar skel_HHmm
[] = { 0x0048, 0x0048, 0x006D, 0x006D, 0 };
398 static const UChar skel_hhmm
[] = { 0x0068, 0x0068, 0x006D, 0x006D, 0 };
399 static const UChar skel_mmss
[] = { 0x006D, 0x006D, 0x0073, 0x0073, 0 };
400 static const UChar skel_mmssSS
[] = { 0x006D, 0x006D, 0x0073, 0x0073, 0x0053, 0x0053, 0 };
401 static const UChar patn_hcmm_a
[] = { 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h:mm a */
402 static const UChar patn_HHcmm
[] = { 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0 }; /* HH:mm */
403 static const UChar patn_hhcmm_a
[] = { 0x0068, 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh:mm a */
404 static const UChar patn_HHpmm
[] = { 0x0048, 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* HH.mm */
405 static const UChar patn_hpmm_a
[] = { 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h.mm a */
406 static const UChar patn_Hpmm
[] = { 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* H.mm */
407 static const UChar patn_hhpmm_a
[] = { 0x0068, 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh.mm a */
408 static const UChar patn_mmcss
[] = { 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0 }; /* mm:ss */
409 static const UChar patn_mmcsspSS
[]= { 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x002E, 0x0053, 0x0053, 0 }; /* mm:ss.SS */
411 static void TestOptions() {
412 const DTPtnGenOptionsData testData
[] = {
413 /*loc skel options expectedPattern */
414 { "en", skel_Hmm
, UDATPG_MATCH_NO_OPTIONS
, patn_HHcmm
},
415 { "en", skel_HHmm
, UDATPG_MATCH_NO_OPTIONS
, patn_HHcmm
},
416 { "en", skel_hhmm
, UDATPG_MATCH_NO_OPTIONS
, patn_hcmm_a
},
417 { "en", skel_Hmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_HHcmm
},
418 { "en", skel_HHmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_HHcmm
},
419 { "en", skel_hhmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_hhcmm_a
},
420 { "da", skel_Hmm
, UDATPG_MATCH_NO_OPTIONS
, patn_HHpmm
},
421 { "da", skel_HHmm
, UDATPG_MATCH_NO_OPTIONS
, patn_HHpmm
},
422 { "da", skel_hhmm
, UDATPG_MATCH_NO_OPTIONS
, patn_hpmm_a
},
423 { "da", skel_Hmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_Hpmm
},
424 { "da", skel_HHmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_HHpmm
},
425 { "da", skel_hhmm
, UDATPG_MATCH_HOUR_FIELD_LENGTH
, patn_hhpmm_a
},
426 { "en_JP@calendar=japanese", skel_mmss
, UDATPG_MATCH_NO_OPTIONS
, patn_mmcss
},
427 { "en_JP@calendar=japanese", skel_mmssSS
, UDATPG_MATCH_NO_OPTIONS
, patn_mmcsspSS
},
430 int count
= UPRV_LENGTHOF(testData
);
431 const DTPtnGenOptionsData
* testDataPtr
= testData
;
433 for (; count
-- > 0; ++testDataPtr
) {
434 UErrorCode status
= U_ZERO_ERROR
;
435 UDateTimePatternGenerator
* dtpgen
= udatpg_open(testDataPtr
->locale
, &status
);
436 if ( U_SUCCESS(status
) ) {
437 UChar pattern
[kTestOptionsPatLenMax
];
438 int32_t patLen
= udatpg_getBestPatternWithOptions(dtpgen
, testDataPtr
->skel
, -1,
439 testDataPtr
->options
, pattern
,
440 kTestOptionsPatLenMax
, &status
);
441 if ( U_FAILURE(status
) || u_strncmp(pattern
, testDataPtr
->expectedPattern
, patLen
+1) != 0 ) {
442 char skelBytes
[kTestOptionsPatLenMax
];
443 char expectedPatternBytes
[kTestOptionsPatLenMax
];
444 char patternBytes
[kTestOptionsPatLenMax
];
445 log_err("ERROR udatpg_getBestPatternWithOptions, locale %s, skeleton %s, options 0x%04X, expected pattern %s, got %s, status %d\n",
446 testDataPtr
->locale
, u_austrncpy(skelBytes
,testDataPtr
->skel
,kTestOptionsPatLenMax
), testDataPtr
->options
,
447 u_austrncpy(expectedPatternBytes
,testDataPtr
->expectedPattern
,kTestOptionsPatLenMax
),
448 u_austrncpy(patternBytes
,pattern
,kTestOptionsPatLenMax
), status
);
450 udatpg_close(dtpgen
);
452 log_data_err("ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n", testDataPtr
->locale
, myErrorName(status
));
457 typedef struct FieldDisplayNameData
{
459 UDateTimePatternField field
;
460 UDateTimePGDisplayWidth width
;
461 const char * expected
;
462 } FieldDisplayNameData
;
463 enum { kFieldDisplayNameMax
= 32, kFieldDisplayNameBytesMax
= 64};
465 static void TestGetFieldDisplayNames() {
466 const FieldDisplayNameData testData
[] = {
467 /*loc field width expectedName */
468 { "de", UDATPG_QUARTER_FIELD
, UDATPG_WIDE
, "Quartal" },
469 { "de", UDATPG_QUARTER_FIELD
, UDATPG_ABBREVIATED
, "Quart." },
470 { "de", UDATPG_QUARTER_FIELD
, UDATPG_NARROW
, "Q" },
471 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_WIDE
, "weekday of the month" },
472 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_ABBREVIATED
, "wkday. of mo." },
473 { "en", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_NARROW
, "wkday. of mo." }, // fallback
474 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_WIDE
, "weekday of the month" },
475 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_ABBREVIATED
, "wkday of mo" }, // override
476 { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD
, UDATPG_NARROW
, "wkday of mo" },
477 { "it", UDATPG_SECOND_FIELD
, UDATPG_WIDE
, "secondo" },
478 { "it", UDATPG_SECOND_FIELD
, UDATPG_ABBREVIATED
, "s" },
479 { "it", UDATPG_SECOND_FIELD
, UDATPG_NARROW
, "s" },
482 int count
= UPRV_LENGTHOF(testData
);
483 const FieldDisplayNameData
* testDataPtr
= testData
;
484 for (; count
-- > 0; ++testDataPtr
) {
485 UErrorCode status
= U_ZERO_ERROR
;
486 UDateTimePatternGenerator
* dtpgen
= udatpg_open(testDataPtr
->locale
, &status
);
487 if ( U_FAILURE(status
) ) {
488 log_data_err("ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n", testDataPtr
->locale
, myErrorName(status
));
490 UChar expName
[kFieldDisplayNameMax
];
491 UChar getName
[kFieldDisplayNameMax
];
492 u_unescape(testDataPtr
->expected
, expName
, kFieldDisplayNameMax
);
494 int32_t getLen
= udatpg_getFieldDisplayName(dtpgen
, testDataPtr
->field
, testDataPtr
->width
,
495 getName
, kFieldDisplayNameMax
, &status
);
496 if ( U_FAILURE(status
) ) {
497 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, got status %s, len %d\n",
498 testDataPtr
->locale
, testDataPtr
->field
, testDataPtr
->width
, u_errorName(status
), getLen
);
499 } else if ( u_strncmp(expName
, getName
, kFieldDisplayNameMax
) != 0 ) {
500 char expNameB
[kFieldDisplayNameBytesMax
];
501 char getNameB
[kFieldDisplayNameBytesMax
];
502 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, expected %s, got %s, status %s\n",
503 testDataPtr
->locale
, testDataPtr
->field
, testDataPtr
->width
,
504 u_austrncpy(expNameB
,expName
,kFieldDisplayNameBytesMax
),
505 u_austrncpy(getNameB
,getName
,kFieldDisplayNameBytesMax
), u_errorName(status
) );
506 } else if (testDataPtr
->width
== UDATPG_WIDE
&& getLen
> 1) {
507 // test preflight & inadequate buffer
509 status
= U_ZERO_ERROR
;
510 getNewLen
= udatpg_getFieldDisplayName(dtpgen
, testDataPtr
->field
, UDATPG_WIDE
, NULL
, 0, &status
);
511 if (U_FAILURE(status
) || getNewLen
!= getLen
) {
512 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, preflight expected len %d, got %d, status %s\n",
513 testDataPtr
->locale
, testDataPtr
->field
, testDataPtr
->width
, getLen
, getNewLen
, u_errorName(status
) );
515 status
= U_ZERO_ERROR
;
516 getNewLen
= udatpg_getFieldDisplayName(dtpgen
, testDataPtr
->field
, UDATPG_WIDE
, getName
, getLen
-1, &status
);
517 if (status
!=U_BUFFER_OVERFLOW_ERROR
|| getNewLen
!= getLen
) {
518 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, overflow expected len %d & BUFFER_OVERFLOW_ERROR, got %d & status %s\n",
519 testDataPtr
->locale
, testDataPtr
->field
, testDataPtr
->width
, getLen
, getNewLen
, u_errorName(status
) );
522 udatpg_close(dtpgen
);
527 enum { kUFmtMax
= 64, kBFmtMax
= 128 };
528 static void TestJapaneseCalendarItems(void) { // rdar://52042600
529 static const UChar
* jaJpnCalSkelAndFmt
[][2] = {
530 { u
"yMd", u
"GGGGGy/MM/dd" },
531 { u
"GGGGGyMd", u
"GGGGGy/MM/dd" },
532 { u
"GyMd", u
"GGGGGy/MM/dd" },
533 { u
"yyMMdd", u
"GGGGGy/MM/dd" },
534 //{ u"GGGGGyyMMdd", u"GGGGGy/MM/dd" },
535 { u
"GyyMMdd", u
"GGGGGy/MM/dd" },
536 { u
"yyMMEdd", u
"GGGGGy/MM/dd(EEE)" },
537 { u
"GGGGGyyMMEdd", u
"GGGGGy/MM/dd(EEE)" },
538 { u
"yyMEdjmma", u
"GGGGGy/MM/dd(EEE) H:mm" },
541 UErrorCode status
= U_ZERO_ERROR
;
542 UDateTimePatternGenerator
* udatpg
= udatpg_open("ja@calendar=japanese", &status
);
543 if ( U_FAILURE(status
) ) {
544 log_data_err("FAIL udatpg_open failed for locale ja@calendar=japanese : %s\n", myErrorName(status
));
547 for (idx
= 0; jaJpnCalSkelAndFmt
[idx
][0] != NULL
; idx
++) {
548 UChar uget
[kUFmtMax
];
549 char bskel
[kBFmtMax
];
550 status
= U_ZERO_ERROR
;
551 u_strToUTF8(bskel
, kBFmtMax
, NULL
, jaJpnCalSkelAndFmt
[idx
][0], -1, &status
);
552 int32_t ulen
= udatpg_getBestPattern(udatpg
, jaJpnCalSkelAndFmt
[idx
][0], -1, uget
, kUFmtMax
, &status
);
553 if ( U_FAILURE(status
) ) {
554 log_data_err("FAIL udatpg_getBestPattern status for skeleton %s : %s\n", bskel
);
555 } else if (u_strcmp(uget
,jaJpnCalSkelAndFmt
[idx
][1]) != 0) {
558 u_strToUTF8(bexp
, kBFmtMax
, NULL
, jaJpnCalSkelAndFmt
[idx
][1], -1, &status
);
559 u_strToUTF8(bget
, kBFmtMax
, NULL
, uget
, ulen
, &status
);
560 log_data_err("ERROR udatpg_getBestPattern for skeleton %s, expect %s, get %s\n", bskel
, bexp
, bget
);
563 udatpg_close(udatpg
);
567 static void TestCountryFallback(void) {
568 // (The list of test locales here is derived from the one in TestCountryFallback() in cnumtst.c)
569 // column 1 is the locale, column 2 is the input skeleton, column 3 is the expected pattern
570 UChar
* testData
[] = {
571 // The following locales are specifically mentioned in Radars:
572 u
"fr_US", u
"GyMMMM", u
"MMMM y G", // rdar://problem/54886964
573 u
"en_TH", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
574 u
"en_BG", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
575 u
"en_LI", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
576 u
"en_MC", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
577 u
"en_MD", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
578 u
"en_VA", u
"GyMMMM", u
"MMMM y G", // rdar://problem/29299919
579 u
"fr_GB", u
"GyMMMM", u
"MMMM y G", // rdar://problem/36020946
580 u
"fr_CN", u
"GyMMMM", u
"MMMM y G", // rdar://problem/50083902
581 u
"es_IE", u
"GyMMMM", u
"MMMM 'de' y G", // rdar://problem/58733843
582 // Special for en_SA, date formats should match en_001, other items should match en
583 u
"en_SA", u
"GyMMMM", u
"MMMM y G",
584 // Tests for situations where the default calendar is different depending on whether you
585 // fall back by language or by country:
586 u
"ar_US", u
"GyMMMM", u
"MMMM y G",
587 // Tests for situations where the original locale ID specifies a script:
588 u
"sr_Cyrl_SA", u
"GyMMMM", u
"MMMM y. G",
589 u
"ru_Cyrl_BA", u
"GyMMMM", u
"LLLL y G",
590 // And these are just a few additional arbitrary combinations:
591 u
"ja_US", u
"GyMMMM", u
"Gy年M月",
592 u
"fr_DE", u
"GyMMMM", u
"MMMM y G",
593 u
"es_TW", u
"GyMMMM", u
"MMMM 'de' y G",
594 // Test to make sure that nothing goes wrong if language and country fallback both lead to the same resource
595 // (This won't happen for any "real" locales, because ICU has resources for all of them, but we can fake it with
596 // a nonexistent country code such as QQ.)
597 u
"en_QQ", u
"GyMMMM", u
"MMMM y G",
599 // The following locales are specifically mentioned in Radars:
600 u
"fr_US", u
"yMEd", u
"EEE, M/d/y", // rdar://problem/54886964
601 u
"en_TH", u
"yMEd", u
"EEE, dd/MM/y GGGGG", // rdar://problem/29299919
602 u
"en_BG", u
"yMEd", u
"EEE, d.MM.y", // rdar://problem/29299919
603 u
"en_LI", u
"yMEd", u
"EEE d.M.y", // rdar://problem/29299919
604 u
"en_MC", u
"yMEd", u
"EEE dd/MM/y", // rdar://problem/29299919
605 u
"en_MD", u
"yMEd", u
"EEE, dd.MM.y", // rdar://problem/29299919
606 u
"en_VA", u
"yMEd", u
"EEE d/M/y", // rdar://problem/29299919
607 u
"fr_GB", u
"yMEd", u
"EEE, dd/MM/y", // rdar://problem/36020946
608 u
"fr_CN", u
"yMEd", u
"y/M/dEEE", // rdar://problem/50083902
609 u
"es_IE", u
"yMEd", u
"EEE, d/M/y", // rdar://problem/58733843
610 // Special for en_SA, date formats should match en_001, other items should match en
611 u
"en_SA", u
"yMEd", u
"EEE, dd/MM/y GGGGG",
612 // Tests for situations where the default calendar is different depending on whether you
613 // fall back by language or by country:
614 u
"ar_US", u
"yMEd", u
"EEE, M/d/y",
615 // Tests for situations where the original locale ID specifies a script:
616 u
"sr_Cyrl_SA", u
"yMEd", u
"EEE, d.M.y. GGGGG",
617 u
"ru_Cyrl_BA", u
"yMEd", u
"EEE, dd.MM.y.",
618 // And these are just a few additional arbitrary combinations:
619 u
"ja_US", u
"yMEd", u
"EEE, M/d/y",
620 u
"fr_DE", u
"yMEd", u
"EEE d.M.y",
621 u
"es_TW", u
"yMEd", u
"y/M/d(EEE)",
622 // Test to make sure that nothing goes wrong if language and country fallback both lead to the same resource
623 // (This won't happen for any "real" locales, because ICU has resources for all of them, but we can fake it with
624 // a nonexistent country code such as QQ.)
625 u
"en_QQ", u
"yMEd", u
"EEE, M/d/y",
627 // The following locales are specifically mentioned in Radars:
628 u
"fr_US", u
"Ejm", u
"EEE h:mm a", // rdar://problem/54886964
629 u
"en_TH", u
"Ejm", u
"EEE, HH:mm", // rdar://problem/29299919
630 u
"en_BG", u
"Ejm", u
"EEE HH:mm", // rdar://problem/29299919
631 u
"en_LI", u
"Ejm", u
"EEE HH:mm", // rdar://problem/29299919
632 u
"en_MC", u
"Ejm", u
"EEE HH:mm", // rdar://problem/29299919
633 u
"en_MD", u
"Ejm", u
"EEE HH:mm", // rdar://problem/29299919
634 u
"en_VA", u
"Ejm", u
"EEE HH:mm", // rdar://problem/29299919
635 u
"fr_GB", u
"Ejm", u
"EEE HH:mm", // rdar://problem/36020946
636 u
"fr_CN", u
"Ejm", u
"EEE h:mm a", // rdar://problem/50083902
637 u
"es_IE", u
"Ejm", u
"EEE, H:mm", // rdar://problem/58733843
638 // Special for en_SA, date formats should match en_001, other items should match en
639 u
"en_SA", u
"Ejm", u
"EEE, h:mm a",
640 // Tests for situations where the default calendar is different depending on whether you
641 // fall back by language or by country:
642 u
"ar_US", u
"Ejm", u
"EEE h:mm\u00a0a",
643 // Tests for situations where the original locale ID specifies a script:
644 u
"sr_Cyrl_SA", u
"Ejm", u
"EEE hh:mm a",
645 u
"ru_Cyrl_BA", u
"Ejm", u
"EEE HH:mm",
646 // And these are just a few additional arbitrary combinations:
647 u
"ja_US", u
"Ejm", u
"EEE aK:mm",
648 u
"fr_DE", u
"Ejm", u
"EEE HH:mm",
649 u
"es_TW", u
"Ejm", u
"EEE, h:mm a",
650 // Test to make sure that nothing goes wrong if language and country fallback both lead to the same resource
651 // (This won't happen for any "real" locales, because ICU has resources for all of them, but we can fake it with
652 // a nonexistent country code such as QQ.)
653 u
"en_QQ", u
"Ejm", u
"EEE HH:mm",
655 // Tests for rdar://64948924 (D431/18A314: Incorrect date format in description: th_US)
656 u
"th_TH", u
"Gy", u
"G y",
657 u
"th_TH", u
"y", u
"G y",
658 u
"th_TH@calendar=gregorian", u
"Gy", u
"G y",
659 u
"th_TH@calendar=gregorian", u
"y", u
"y",
660 u
"th_US", u
"Gy", u
"G y",
664 for (int32_t i
= 0; i
< (sizeof(testData
) / sizeof(UChar
*)); i
+= 3) {
665 UChar
* localeU
= testData
[i
];
667 UChar
* skeleton
= testData
[i
+ 1];
668 UChar
* expectedPattern
= testData
[i
+ 2];
670 u_austrcpy(locale
, localeU
);
672 UErrorCode err
= U_ZERO_ERROR
;
673 UDateTimePatternGenerator
* dtpg
= udatpg_open(locale
, &err
);
674 if (assertSuccess("Failed to open UDateTimePatternGenerator", &err
)) {
675 UChar actualPattern
[200];
677 udatpg_getBestPattern(dtpg
, skeleton
, -1, actualPattern
, 200, &err
);
679 if (assertSuccess("Error getting pattern with skeleton", &err
)) {
680 char errorMessage
[200];
681 sprintf(errorMessage
, "In %s, pattern for skeleton %s doesn't match\n", locale
, austrdup(skeleton
));
682 assertUEquals(errorMessage
, expectedPattern
, actualPattern
);
689 // Test for rdar://65281358: Make sure DateTimePatternGenerator supplies an era field for year formats using the
690 // Buddhist and Japanese calendars for all English-speaking locales.
691 static void TestEras(void) {
692 char* localeIDs
[] = {
693 "en_US@calendar=japanese",
694 "en_GB@calendar=japanese",
695 "en_150@calendar=japanese",
696 "en_001@calendar=japanese",
697 "en@calendar=japanese",
698 "en_US@calendar=buddhist",
699 "en_GB@calendar=buddhist",
700 "en_150@calendar=buddhist",
701 "en_001@calendar=buddhist",
702 "en@calendar=buddhist",
705 UErrorCode err
= U_ZERO_ERROR
;
706 for (int32_t i
= 0; i
< UPRV_LENGTHOF(localeIDs
); i
++) {
707 char* locale
= localeIDs
[i
];
708 UDateTimePatternGenerator
* dtpg
= udatpg_open(locale
, &err
);
709 if (U_SUCCESS(err
)) {
711 udatpg_getBestPattern(dtpg
, u
"y", 1, pattern
, 200, &err
);
713 if (u_strchr(pattern
, u
'G') == NULL
) {
714 log_err("missing era field for locale %s\n", locale
);