• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 *   Copyright (C) 2007-2016, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 *******************************************************************************
10 *   file name:  udatpg_test.c
11 *   encoding:   UTF-8
12 *   tab size:   8 (not used)
13 *   indentation:4
14 *
15 *   created on: 2007aug01
16 *   created by: Markus W. Scherer
17 *
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.
21 *
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.)
26 */
27 
28 #include "unicode/utypes.h"
29 
30 #if !UCONFIG_NO_FORMATTING
31 #include "unicode/udat.h"
32 #include "unicode/udatpg.h"
33 #include "unicode/ustring.h"
34 #include "cintltst.h"
35 #include "cmemory.h"
36 
37 void addDateTimePatternGeneratorTest(TestNode** root);
38 
39 #define TESTCASE(x) addTest(root, &x, "tsformat/udatpg_test/" #x)
40 
41 static void TestOpenClose(void);
42 static void TestUsage(void);
43 static void TestBuilder(void);
44 static void TestOptions(void);
45 static void TestGetFieldDisplayNames(void);
46 static void TestGetDefaultHourCycle(void);
47 static void TestGetDefaultHourCycleOnEmptyInstance(void);
48 
addDateTimePatternGeneratorTest(TestNode ** root)49 void addDateTimePatternGeneratorTest(TestNode** root) {
50     TESTCASE(TestOpenClose);
51     TESTCASE(TestUsage);
52     TESTCASE(TestBuilder);
53     TESTCASE(TestOptions);
54     TESTCASE(TestGetFieldDisplayNames);
55     TESTCASE(TestGetDefaultHourCycle);
56     TESTCASE(TestGetDefaultHourCycleOnEmptyInstance);
57 }
58 
59 /*
60  * Pipe symbol '|'. We pass only the first UChar without NUL-termination.
61  * The second UChar is just to verify that the API does not pick that up.
62  */
63 static const UChar pipeString[]={ 0x7c, 0x0a };
64 
65 static const UChar testSkeleton1[]={ 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
66 static const UChar expectingBestPattern[]={ 0x48, 0x2e, 0x6d, 0x6d, 0 }; /* H.mm */
67 static const UChar testPattern[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0 }; /* HH:mm */
68 static const UChar expectingSkeleton[]= { 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
69 static const UChar expectingBaseSkeleton[]= { 0x48, 0x6d, 0 }; /* HHmm */
70 static const UChar redundantPattern[]={ 0x79, 0x79, 0x4d, 0x4d, 0x4d, 0 }; /* yyMMM */
71 static const UChar testFormat[]= {0x7B, 0x31, 0x7D, 0x20, 0x7B, 0x30, 0x7D, 0};  /* {1} {0} */
72 static const UChar appendItemName[]= {0x68, 0x72, 0};  /* hr */
73 static const UChar testPattern2[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x20, 0x76, 0 }; /* HH:mm v */
74 static const UChar replacedStr[]={ 0x76, 0x76, 0x76, 0x76, 0 }; /* vvvv */
75 /* results for getBaseSkeletons() - {Hmv}, {yMMM} */
76 static const UChar resultBaseSkeletons[2][10] = {{0x48,0x6d, 0x76, 0}, {0x79, 0x4d, 0x4d, 0x4d, 0 } };
77 static const UChar sampleFormatted[] = {0x31, 0x30, 0x20, 0x6A, 0x75, 0x69, 0x6C, 0x2E, 0}; /* 10 juil. */
78 static const UChar skeleton[]= {0x4d, 0x4d, 0x4d, 0x64, 0};  /* MMMd */
79 static const UChar timeZoneGMT[] = { 0x0047, 0x004d, 0x0054, 0x0000 };  /* "GMT" */
80 
TestOpenClose()81 static void TestOpenClose() {
82     UErrorCode errorCode=U_ZERO_ERROR;
83     UDateTimePatternGenerator *dtpg, *dtpg2;
84     const UChar *s;
85     int32_t length;
86 
87     /* Open a DateTimePatternGenerator for the default locale. */
88     dtpg=udatpg_open(NULL, &errorCode);
89     if(U_FAILURE(errorCode)) {
90         log_err_status(errorCode, "udatpg_open(NULL) failed - %s\n", u_errorName(errorCode));
91         return;
92     }
93     udatpg_close(dtpg);
94 
95     /* Now one for German. */
96     dtpg=udatpg_open("de", &errorCode);
97     if(U_FAILURE(errorCode)) {
98         log_err("udatpg_open(de) failed - %s\n", u_errorName(errorCode));
99         return;
100     }
101 
102     /* Make some modification which we verify gets passed on to the clone. */
103     udatpg_setDecimal(dtpg, pipeString, 1);
104 
105     /* Clone the generator. */
106     dtpg2=udatpg_clone(dtpg, &errorCode);
107     if(U_FAILURE(errorCode) || dtpg2==NULL) {
108         log_err("udatpg_clone() failed - %s\n", u_errorName(errorCode));
109         return;
110     }
111 
112     /* Verify that the clone has the custom decimal symbol. */
113     s=udatpg_getDecimal(dtpg2, &length);
114     if(s==pipeString || length!=1 || 0!=u_memcmp(s, pipeString, length) || s[length]!=0) {
115         log_err("udatpg_getDecimal(cloned object) did not return the expected string\n");
116         return;
117     }
118 
119     udatpg_close(dtpg);
120     udatpg_close(dtpg2);
121 }
122 
123 typedef struct {
124     UDateTimePatternField field;
125     UChar name[12];
126 } AppendItemNameData;
127 
128 static const AppendItemNameData appendItemNameData[] = { /* for Finnish */
129     { UDATPG_YEAR_FIELD,    {0x0076,0x0075,0x006F,0x0073,0x0069,0} }, /* "vuosi" */
130     { UDATPG_MONTH_FIELD,   {0x006B,0x0075,0x0075,0x006B,0x0061,0x0075,0x0073,0x0069,0} }, /* "kuukausi" */
131     { UDATPG_WEEKDAY_FIELD, {0x0076,0x0069,0x0069,0x006B,0x006F,0x006E,0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
132     { UDATPG_DAY_FIELD,     {0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
133     { UDATPG_HOUR_FIELD,    {0x0074,0x0075,0x006E,0x0074,0x0069,0} }, /* "tunti" */
134     { UDATPG_FIELD_COUNT,   {0}        }  /* terminator */
135 };
136 
TestUsage()137 static void TestUsage() {
138     UErrorCode errorCode=U_ZERO_ERROR;
139     UDateTimePatternGenerator *dtpg;
140     const AppendItemNameData * appItemNameDataPtr;
141     UChar bestPattern[20];
142     UChar result[20];
143     int32_t length;
144     UChar *s;
145     const UChar *r;
146 
147     dtpg=udatpg_open("fi", &errorCode);
148     if(U_FAILURE(errorCode)) {
149         log_err_status(errorCode, "udatpg_open(fi) failed - %s\n", u_errorName(errorCode));
150         return;
151     }
152     length = udatpg_getBestPattern(dtpg, testSkeleton1, 4,
153                                    bestPattern, 20, &errorCode);
154     if(U_FAILURE(errorCode)) {
155         log_err("udatpg_getBestPattern failed - %s\n", u_errorName(errorCode));
156         return;
157     }
158     if((u_memcmp(bestPattern, expectingBestPattern, length)!=0) || bestPattern[length]!=0) {
159         log_err("udatpg_getBestPattern did not return the expected string\n");
160         return;
161     }
162 
163 
164     /* Test skeleton == NULL */
165     s=NULL;
166     length = udatpg_getBestPattern(dtpg, s, 0, bestPattern, 20, &errorCode);
167     if(!U_FAILURE(errorCode)&&(length!=0) ) {
168         log_err("udatpg_getBestPattern failed in illegal argument - skeleton is NULL.\n");
169         return;
170     }
171 
172     /* Test udatpg_getSkeleton */
173     length = udatpg_getSkeleton(dtpg, testPattern, 5, result, 20,  &errorCode);
174     if(U_FAILURE(errorCode)) {
175         log_err("udatpg_getSkeleton failed - %s\n", u_errorName(errorCode));
176         return;
177     }
178     if((u_memcmp(result, expectingSkeleton, length)!=0) || result[length]!=0) {
179         log_err("udatpg_getSkeleton did not return the expected string\n");
180         return;
181     }
182 
183     /* Test pattern == NULL */
184     s=NULL;
185     length = udatpg_getSkeleton(dtpg, s, 0, result, 20, &errorCode);
186     if(!U_FAILURE(errorCode)&&(length!=0) ) {
187         log_err("udatpg_getSkeleton failed in illegal argument - pattern is NULL.\n");
188         return;
189     }
190 
191     /* Test udatpg_getBaseSkeleton */
192     length = udatpg_getBaseSkeleton(dtpg, testPattern, 5, result, 20,  &errorCode);
193     if(U_FAILURE(errorCode)) {
194         log_err("udatpg_getBaseSkeleton failed - %s\n", u_errorName(errorCode));
195         return;
196     }
197     if((u_memcmp(result, expectingBaseSkeleton, length)!=0) || result[length]!=0) {
198         log_err("udatpg_getBaseSkeleton did not return the expected string\n");
199         return;
200     }
201 
202     /* Test pattern == NULL */
203     s=NULL;
204     length = udatpg_getBaseSkeleton(dtpg, s, 0, result, 20, &errorCode);
205     if(!U_FAILURE(errorCode)&&(length!=0) ) {
206         log_err("udatpg_getBaseSkeleton failed in illegal argument - pattern is NULL.\n");
207         return;
208     }
209 
210     /* set append format to {1}{0} */
211     udatpg_setAppendItemFormat( dtpg, UDATPG_MONTH_FIELD, testFormat, 7 );
212     r = udatpg_getAppendItemFormat(dtpg, UDATPG_MONTH_FIELD, &length);
213 
214 
215     if(length!=7 || 0!=u_memcmp(r, testFormat, length) || r[length]!=0) {
216         log_err("udatpg_setAppendItemFormat did not return the expected string\n");
217         return;
218     }
219 
220     for (appItemNameDataPtr = appendItemNameData; appItemNameDataPtr->field <  UDATPG_FIELD_COUNT; appItemNameDataPtr++) {
221         int32_t nameLength;
222         const UChar * namePtr = udatpg_getAppendItemName(dtpg, appItemNameDataPtr->field, &nameLength);
223         if ( namePtr == NULL || u_strncmp(appItemNameDataPtr->name, namePtr, nameLength) != 0 ) {
224             log_err("udatpg_getAppendItemName returns invalid name for field %d\n", (int)appItemNameDataPtr->field);
225         }
226     }
227 
228     /* set append name to hr */
229     udatpg_setAppendItemName(dtpg, UDATPG_HOUR_FIELD, appendItemName, 2);
230     r = udatpg_getAppendItemName(dtpg, UDATPG_HOUR_FIELD, &length);
231 
232     if(length!=2 || 0!=u_memcmp(r, appendItemName, length) || r[length]!=0) {
233         log_err("udatpg_setAppendItemName did not return the expected string\n");
234         return;
235     }
236 
237     /* set date time format to {1}{0} */
238     udatpg_setDateTimeFormat( dtpg, testFormat, 7 );
239     r = udatpg_getDateTimeFormat(dtpg, &length);
240 
241     if(length!=7 || 0!=u_memcmp(r, testFormat, length) || r[length]!=0) {
242         log_err("udatpg_setDateTimeFormat did not return the expected string\n");
243         return;
244     }
245     udatpg_close(dtpg);
246 }
247 
TestBuilder()248 static void TestBuilder() {
249     UErrorCode errorCode=U_ZERO_ERROR;
250     UDateTimePatternGenerator *dtpg;
251     UDateTimePatternConflict conflict;
252     UEnumeration *en;
253     UChar result[20];
254     int32_t length, pLength;
255     const UChar *s, *p;
256     const UChar* ptrResult[2];
257     int32_t count=0;
258     UDateTimePatternGenerator *generator;
259     int32_t formattedCapacity, resultLen,patternCapacity ;
260     UChar   pattern[40], formatted[40];
261     UDateFormat *formatter;
262     UDate sampleDate = 837039928046.0;
263     static const char locale[]= "fr";
264     UErrorCode status=U_ZERO_ERROR;
265 
266     /* test create an empty DateTimePatternGenerator */
267     dtpg=udatpg_openEmpty(&errorCode);
268     if(U_FAILURE(errorCode)) {
269         log_err("udatpg_openEmpty() failed - %s\n", u_errorName(errorCode));
270         return;
271     }
272 
273     /* Add a pattern */
274     conflict = udatpg_addPattern(dtpg, redundantPattern, 5, FALSE, result, 20,
275                                  &length, &errorCode);
276     if(U_FAILURE(errorCode)) {
277         log_err("udatpg_addPattern() failed - %s\n", u_errorName(errorCode));
278         return;
279     }
280     /* Add a redundant pattern */
281     conflict = udatpg_addPattern(dtpg, redundantPattern, 5, FALSE, result, 20,
282                                  &length, &errorCode);
283     if(conflict == UDATPG_NO_CONFLICT) {
284         log_err("udatpg_addPattern() failed to find the duplicate pattern.\n");
285         return;
286     }
287     /* Test pattern == NULL */
288     s=NULL;
289     length = udatpg_addPattern(dtpg, s, 0, FALSE, result, 20,
290                                &length, &errorCode);
291     if(!U_FAILURE(errorCode)&&(length!=0) ) {
292         log_err("udatpg_addPattern failed in illegal argument - pattern is NULL.\n");
293         return;
294     }
295 
296     /* replace field type */
297     errorCode=U_ZERO_ERROR;
298     conflict = udatpg_addPattern(dtpg, testPattern2, 7, FALSE, result, 20,
299                                  &length, &errorCode);
300     if((conflict != UDATPG_NO_CONFLICT)||U_FAILURE(errorCode)) {
301         log_err("udatpg_addPattern() failed to add HH:mm v. - %s\n", u_errorName(errorCode));
302         return;
303     }
304     length = udatpg_replaceFieldTypes(dtpg, testPattern2, 7, replacedStr, 4,
305                                       result, 20, &errorCode);
306     if (U_FAILURE(errorCode) || (length==0) ) {
307         log_err("udatpg_replaceFieldTypes failed!\n");
308         return;
309     }
310 
311     /* Get all skeletons and the crroespong pattern for each skeleton. */
312     ptrResult[0] = testPattern2;
313     ptrResult[1] = redundantPattern;
314     count=0;
315     en = udatpg_openSkeletons(dtpg, &errorCode);
316     if (U_FAILURE(errorCode) || (length==0) ) {
317         log_err("udatpg_openSkeletons failed!\n");
318         return;
319     }
320     while ( (s=uenum_unext(en, &length, &errorCode))!= NULL) {
321         p = udatpg_getPatternForSkeleton(dtpg, s, length, &pLength);
322         if (U_FAILURE(errorCode) || p==NULL || u_memcmp(p, ptrResult[count], pLength)!=0 ) {
323             log_err("udatpg_getPatternForSkeleton failed!\n");
324             return;
325         }
326         count++;
327     }
328     uenum_close(en);
329 
330     /* Get all baseSkeletons */
331     en = udatpg_openBaseSkeletons(dtpg, &errorCode);
332     count=0;
333     while ( (s=uenum_unext(en, &length, &errorCode))!= NULL) {
334         p = udatpg_getPatternForSkeleton(dtpg, s, length, &pLength);
335         if (U_FAILURE(errorCode) || p==NULL || u_memcmp(p, resultBaseSkeletons[count], pLength)!=0 ) {
336             log_err("udatpg_getPatternForSkeleton failed!\n");
337             return;
338         }
339         count++;
340     }
341     if (U_FAILURE(errorCode) || (length==0) ) {
342         log_err("udatpg_openSkeletons failed!\n");
343         return;
344     }
345     uenum_close(en);
346 
347     udatpg_close(dtpg);
348 
349     /* sample code in Userguide */
350     patternCapacity = UPRV_LENGTHOF(pattern);
351     status=U_ZERO_ERROR;
352     generator=udatpg_open(locale, &status);
353     if(U_FAILURE(status)) {
354         return;
355     }
356 
357     /* get a pattern for an abbreviated month and day */
358     length = udatpg_getBestPattern(generator, skeleton, 4,
359                                    pattern, patternCapacity, &status);
360     formatter = udat_open(UDAT_PATTERN, UDAT_PATTERN, locale, timeZoneGMT, -1,
361                           pattern, length, &status);
362     if (formatter==NULL) {
363         log_err("Failed to initialize the UDateFormat of the sample code in Userguide.\n");
364         udatpg_close(generator);
365         return;
366     }
367 
368     /* use it to format (or parse) */
369     formattedCapacity = UPRV_LENGTHOF(formatted);
370     resultLen=udat_format(formatter, ucal_getNow(), formatted, formattedCapacity,
371                           NULL, &status);
372     /* for French, the result is "13 sept." */
373 
374     /* cannot use the result from ucal_getNow() because the value change evreyday. */
375     resultLen=udat_format(formatter, sampleDate, formatted, formattedCapacity,
376                           NULL, &status);
377     if ( u_memcmp(sampleFormatted, formatted, resultLen) != 0 ) {
378         log_err("Failed udat_format() of sample code in Userguide.\n");
379     }
380     udatpg_close(generator);
381     udat_close(formatter);
382 }
383 
384 typedef struct DTPtnGenOptionsData {
385     const char *                    locale;
386     const UChar *                   skel;
387     UDateTimePatternMatchOptions    options;
388     const UChar *                   expectedPattern;
389 } DTPtnGenOptionsData;
390 enum { kTestOptionsPatLenMax = 32 };
391 
392 static const UChar skel_Hmm[]     = { 0x0048, 0x006D, 0x006D, 0 };
393 static const UChar skel_HHmm[]    = { 0x0048, 0x0048, 0x006D, 0x006D, 0 };
394 static const UChar skel_hhmm[]    = { 0x0068, 0x0068, 0x006D, 0x006D, 0 };
395 static const UChar patn_hcmm_a[]  = { 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h:mm a */
396 static const UChar patn_HHcmm[]   = { 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0 }; /* HH:mm */
397 static const UChar patn_hhcmm_a[] = { 0x0068, 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh:mm a */
398 static const UChar patn_HHpmm[]   = { 0x0048, 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* HH.mm */
399 static const UChar patn_hpmm_a[]  = { 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h.mm a */
400 static const UChar patn_Hpmm[]    = { 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* H.mm */
401 static const UChar patn_hhpmm_a[] = { 0x0068, 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh.mm a */
402 
TestOptions()403 static void TestOptions() {
404     const DTPtnGenOptionsData testData[] = {
405         /*loc   skel       options                       expectedPattern */
406         { "en", skel_Hmm,  UDATPG_MATCH_NO_OPTIONS,        patn_HHcmm   },
407         { "en", skel_HHmm, UDATPG_MATCH_NO_OPTIONS,        patn_HHcmm   },
408         { "en", skel_hhmm, UDATPG_MATCH_NO_OPTIONS,        patn_hcmm_a  },
409         { "en", skel_Hmm,  UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHcmm   },
410         { "en", skel_HHmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHcmm   },
411         { "en", skel_hhmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_hhcmm_a },
412         { "da", skel_Hmm,  UDATPG_MATCH_NO_OPTIONS,        patn_HHpmm   },
413         { "da", skel_HHmm, UDATPG_MATCH_NO_OPTIONS,        patn_HHpmm   },
414         { "da", skel_hhmm, UDATPG_MATCH_NO_OPTIONS,        patn_hpmm_a  },
415         { "da", skel_Hmm,  UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_Hpmm    },
416         { "da", skel_HHmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHpmm   },
417         { "da", skel_hhmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_hhpmm_a },
418     };
419 
420     int count = UPRV_LENGTHOF(testData);
421     const DTPtnGenOptionsData * testDataPtr = testData;
422 
423     for (; count-- > 0; ++testDataPtr) {
424         UErrorCode status = U_ZERO_ERROR;
425         UDateTimePatternGenerator * dtpgen = udatpg_open(testDataPtr->locale, &status);
426         if ( U_SUCCESS(status) ) {
427             UChar pattern[kTestOptionsPatLenMax];
428             int32_t patLen = udatpg_getBestPatternWithOptions(dtpgen, testDataPtr->skel, -1,
429                                                               testDataPtr->options, pattern,
430                                                               kTestOptionsPatLenMax, &status);
431             if ( U_FAILURE(status) || u_strncmp(pattern, testDataPtr->expectedPattern, patLen+1) != 0 ) {
432                 char skelBytes[kTestOptionsPatLenMax];
433                 char expectedPatternBytes[kTestOptionsPatLenMax];
434                 char patternBytes[kTestOptionsPatLenMax];
435                 log_err("ERROR udatpg_getBestPatternWithOptions, locale %s, skeleton %s, options 0x%04X, expected pattern %s, got %s, status %d\n",
436                         testDataPtr->locale, u_austrncpy(skelBytes,testDataPtr->skel,kTestOptionsPatLenMax), testDataPtr->options,
437                         u_austrncpy(expectedPatternBytes,testDataPtr->expectedPattern,kTestOptionsPatLenMax),
438                         u_austrncpy(patternBytes,pattern,kTestOptionsPatLenMax), status );
439             }
440             udatpg_close(dtpgen);
441         } else {
442             log_data_err("ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n", testDataPtr->locale, myErrorName(status));
443         }
444     }
445 }
446 
447 typedef struct FieldDisplayNameData {
448     const char *            locale;
449     UDateTimePatternField   field;
450     UDateTimePGDisplayWidth width;
451     const char *            expected;
452 } FieldDisplayNameData;
453 enum { kFieldDisplayNameMax = 32, kFieldDisplayNameBytesMax  = 64};
454 
TestGetFieldDisplayNames()455 static void TestGetFieldDisplayNames() {
456     const FieldDisplayNameData testData[] = {
457         /*loc      field                              width               expectedName */
458         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_WIDE,        "Quartal" },
459         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_ABBREVIATED, "Quart." },
460         { "de",    UDATPG_QUARTER_FIELD,              UDATPG_NARROW,      "Q" },
461         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE,        "weekday of the month" },
462         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday. of mo." },
463         { "en",    UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW,      "wkday. of mo." }, // fallback
464         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_WIDE,        "weekday of the month" },
465         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_ABBREVIATED, "wkday of mo" }, // override
466         { "en_GB", UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, UDATPG_NARROW,      "wkday of mo" },
467         { "it",    UDATPG_SECOND_FIELD,               UDATPG_WIDE,        "secondo" },
468         { "it",    UDATPG_SECOND_FIELD,               UDATPG_ABBREVIATED, "s" },
469         { "it",    UDATPG_SECOND_FIELD,               UDATPG_NARROW,      "s" },
470     };
471 
472     int count = UPRV_LENGTHOF(testData);
473     const FieldDisplayNameData * testDataPtr = testData;
474     for (; count-- > 0; ++testDataPtr) {
475         UErrorCode status = U_ZERO_ERROR;
476         UDateTimePatternGenerator * dtpgen = udatpg_open(testDataPtr->locale, &status);
477         if ( U_FAILURE(status) ) {
478             log_data_err("ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n", testDataPtr->locale, myErrorName(status));
479         } else {
480             UChar expName[kFieldDisplayNameMax];
481             UChar getName[kFieldDisplayNameMax];
482             u_unescape(testDataPtr->expected, expName, kFieldDisplayNameMax);
483 
484             int32_t getLen = udatpg_getFieldDisplayName(dtpgen, testDataPtr->field, testDataPtr->width,
485                                                         getName, kFieldDisplayNameMax, &status);
486             if ( U_FAILURE(status) ) {
487                 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, got status %s, len %d\n",
488                         testDataPtr->locale, testDataPtr->field, testDataPtr->width, u_errorName(status), getLen);
489             } else if ( u_strncmp(expName, getName, kFieldDisplayNameMax) != 0 ) {
490                 char expNameB[kFieldDisplayNameBytesMax];
491                 char getNameB[kFieldDisplayNameBytesMax];
492                 log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, expected %s, got %s, status %s\n",
493                         testDataPtr->locale, testDataPtr->field, testDataPtr->width,
494                         u_austrncpy(expNameB,expName,kFieldDisplayNameBytesMax),
495                         u_austrncpy(getNameB,getName,kFieldDisplayNameBytesMax), u_errorName(status) );
496             } else if (testDataPtr->width == UDATPG_WIDE && getLen > 1) {
497                 // test preflight & inadequate buffer
498                 int32_t getNewLen;
499                 status = U_ZERO_ERROR;
500                 getNewLen = udatpg_getFieldDisplayName(dtpgen, testDataPtr->field, UDATPG_WIDE, NULL, 0, &status);
501                 if (U_FAILURE(status) || getNewLen != getLen) {
502                     log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, preflight expected len %d, got %d, status %s\n",
503                         testDataPtr->locale, testDataPtr->field, testDataPtr->width, getLen, getNewLen, u_errorName(status) );
504                 }
505                 status = U_ZERO_ERROR;
506                 getNewLen = udatpg_getFieldDisplayName(dtpgen, testDataPtr->field, UDATPG_WIDE, getName, getLen-1, &status);
507                 if (status!=U_BUFFER_OVERFLOW_ERROR || getNewLen != getLen) {
508                     log_err("ERROR udatpg_getFieldDisplayName locale %s field %d width %d, overflow expected len %d & BUFFER_OVERFLOW_ERROR, got %d & status %s\n",
509                         testDataPtr->locale, testDataPtr->field, testDataPtr->width, getLen, getNewLen, u_errorName(status) );
510                 }
511             }
512             udatpg_close(dtpgen);
513         }
514     }
515 }
516 
517 typedef struct HourCycleData {
518     const char *         locale;
519     UDateFormatHourCycle   expected;
520 } HourCycleData;
521 
TestGetDefaultHourCycle()522 static void TestGetDefaultHourCycle() {
523     const HourCycleData testData[] = {
524         /*loc      expected */
525         { "ar_EG",    UDAT_HOUR_CYCLE_12 },
526         { "de_DE",    UDAT_HOUR_CYCLE_23 },
527         { "en_AU",    UDAT_HOUR_CYCLE_12 },
528         { "en_CA",    UDAT_HOUR_CYCLE_12 },
529         { "en_US",    UDAT_HOUR_CYCLE_12 },
530         { "es_ES",    UDAT_HOUR_CYCLE_23 },
531         { "fi",       UDAT_HOUR_CYCLE_23 },
532         { "fr",       UDAT_HOUR_CYCLE_23 },
533         { "ja_JP",    UDAT_HOUR_CYCLE_23 },
534         { "zh_CN",    UDAT_HOUR_CYCLE_12 },
535         { "zh_HK",    UDAT_HOUR_CYCLE_12 },
536         { "zh_TW",    UDAT_HOUR_CYCLE_12 },
537         { "ko_KR",    UDAT_HOUR_CYCLE_12 },
538     };
539     int count = UPRV_LENGTHOF(testData);
540     const HourCycleData * testDataPtr = testData;
541     for (; count-- > 0; ++testDataPtr) {
542         UErrorCode status = U_ZERO_ERROR;
543         UDateTimePatternGenerator * dtpgen =
544             udatpg_open(testDataPtr->locale, &status);
545         if ( U_FAILURE(status) ) {
546             log_data_err( "ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n",
547                          testDataPtr->locale, myErrorName(status));
548         } else {
549             UDateFormatHourCycle actual = udatpg_getDefaultHourCycle(dtpgen, &status);
550             if (U_FAILURE(status) || testDataPtr->expected != actual) {
551                 log_err("ERROR dtpgen locale %s udatpg_getDefaultHourCycle expecte to get %d but get %d\n",
552                         testDataPtr->locale, testDataPtr->expected, actual);
553             }
554             udatpg_close(dtpgen);
555         }
556     }
557 }
558 
559 // Ensure that calling udatpg_getDefaultHourCycle on an empty instance doesn't call UPRV_UNREACHABLE/abort.
TestGetDefaultHourCycleOnEmptyInstance()560 static void TestGetDefaultHourCycleOnEmptyInstance() {
561     UErrorCode status = U_ZERO_ERROR;
562     UDateTimePatternGenerator * dtpgen = udatpg_openEmpty(&status);
563 
564     if (U_FAILURE(status)) {
565         log_data_err("ERROR udatpg_openEmpty failed, status: %s \n", myErrorName(status));
566         return;
567     }
568 
569     (void)udatpg_getDefaultHourCycle(dtpgen, &status);
570     if (!U_FAILURE(status)) {
571         log_data_err("ERROR expected udatpg_getDefaultHourCycle on an empty instance to fail, status: %s", myErrorName(status));
572     }
573 
574     status = U_USELESS_COLLATOR_ERROR;
575     (void)udatpg_getDefaultHourCycle(dtpgen, &status);
576     if (status != U_USELESS_COLLATOR_ERROR) {
577         log_data_err("ERROR udatpg_getDefaultHourCycle shouldn't modify status if it is already failed, status: %s", myErrorName(status));
578     }
579 
580     udatpg_close(dtpgen);
581 }
582 
583 #endif
584