1// Copyright (C) 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:   US-ASCII
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
37void addDateTimePatternGeneratorTest(TestNode** root);
38
39#define TESTCASE(x) addTest(root, &x, "tsformat/udatpg_test/" #x)
40
41static void TestOpenClose(void);
42static void TestUsage(void);
43static void TestBuilder(void);
44static void TestOptions(void);
45
46void addDateTimePatternGeneratorTest(TestNode** root) {
47    TESTCASE(TestOpenClose);
48    TESTCASE(TestUsage);
49    TESTCASE(TestBuilder);
50    TESTCASE(TestOptions);
51}
52
53/*
54 * Pipe symbol '|'. We pass only the first UChar without NUL-termination.
55 * The second UChar is just to verify that the API does not pick that up.
56 */
57static const UChar pipeString[]={ 0x7c, 0x0a };
58
59static const UChar testSkeleton1[]={ 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
60static const UChar expectingBestPattern[]={ 0x48, 0x2e, 0x6d, 0x6d, 0 }; /* H.mm */
61static const UChar testPattern[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0 }; /* HH:mm */
62static const UChar expectingSkeleton[]= { 0x48, 0x48, 0x6d, 0x6d, 0 }; /* HHmm */
63static const UChar expectingBaseSkeleton[]= { 0x48, 0x6d, 0 }; /* HHmm */
64static const UChar redundantPattern[]={ 0x79, 0x79, 0x4d, 0x4d, 0x4d, 0 }; /* yyMMM */
65static const UChar testFormat[]= {0x7B, 0x31, 0x7D, 0x20, 0x7B, 0x30, 0x7D, 0};  /* {1} {0} */
66static const UChar appendItemName[]= {0x68, 0x72, 0};  /* hr */
67static const UChar testPattern2[]={ 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x20, 0x76, 0 }; /* HH:mm v */
68static const UChar replacedStr[]={ 0x76, 0x76, 0x76, 0x76, 0 }; /* vvvv */
69/* results for getBaseSkeletons() - {Hmv}, {yMMM} */
70static const UChar resultBaseSkeletons[2][10] = {{0x48,0x6d, 0x76, 0}, {0x79, 0x4d, 0x4d, 0x4d, 0 } };
71static const UChar sampleFormatted[] = {0x31, 0x30, 0x20, 0x6A, 0x75, 0x69, 0x6C, 0x2E, 0}; /* 10 juil. */
72static const UChar skeleton[]= {0x4d, 0x4d, 0x4d, 0x64, 0};  /* MMMd */
73static const UChar timeZoneGMT[] = { 0x0047, 0x004d, 0x0054, 0x0000 };  /* "GMT" */
74
75static void TestOpenClose() {
76    UErrorCode errorCode=U_ZERO_ERROR;
77    UDateTimePatternGenerator *dtpg, *dtpg2;
78    const UChar *s;
79    int32_t length;
80
81    /* Open a DateTimePatternGenerator for the default locale. */
82    dtpg=udatpg_open(NULL, &errorCode);
83    if(U_FAILURE(errorCode)) {
84        log_err_status(errorCode, "udatpg_open(NULL) failed - %s\n", u_errorName(errorCode));
85        return;
86    }
87    udatpg_close(dtpg);
88
89    /* Now one for German. */
90    dtpg=udatpg_open("de", &errorCode);
91    if(U_FAILURE(errorCode)) {
92        log_err("udatpg_open(de) failed - %s\n", u_errorName(errorCode));
93        return;
94    }
95
96    /* Make some modification which we verify gets passed on to the clone. */
97    udatpg_setDecimal(dtpg, pipeString, 1);
98
99    /* Clone the generator. */
100    dtpg2=udatpg_clone(dtpg, &errorCode);
101    if(U_FAILURE(errorCode) || dtpg2==NULL) {
102        log_err("udatpg_clone() failed - %s\n", u_errorName(errorCode));
103        return;
104    }
105
106    /* Verify that the clone has the custom decimal symbol. */
107    s=udatpg_getDecimal(dtpg2, &length);
108    if(s==pipeString || length!=1 || 0!=u_memcmp(s, pipeString, length) || s[length]!=0) {
109        log_err("udatpg_getDecimal(cloned object) did not return the expected string\n");
110        return;
111    }
112
113    udatpg_close(dtpg);
114    udatpg_close(dtpg2);
115}
116
117typedef struct {
118    UDateTimePatternField field;
119    UChar name[12];
120} AppendItemNameData;
121
122static const AppendItemNameData appendItemNameData[] = { /* for Finnish */
123    { UDATPG_YEAR_FIELD,    {0x0076,0x0075,0x006F,0x0073,0x0069,0} }, /* "vuosi" */
124    { UDATPG_MONTH_FIELD,   {0x006B,0x0075,0x0075,0x006B,0x0061,0x0075,0x0073,0x0069,0} }, /* "kuukausi" */
125    { UDATPG_WEEKDAY_FIELD, {0x0076,0x0069,0x0069,0x006B,0x006F,0x006E,0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
126    { UDATPG_DAY_FIELD,     {0x0070,0x00E4,0x0069,0x0076,0x00E4,0} },
127    { UDATPG_HOUR_FIELD,    {0x0074,0x0075,0x006E,0x0074,0x0069,0} }, /* "tunti" */
128    { UDATPG_FIELD_COUNT,   {0}        }  /* terminator */
129};
130
131static void TestUsage() {
132    UErrorCode errorCode=U_ZERO_ERROR;
133    UDateTimePatternGenerator *dtpg;
134    const AppendItemNameData * appItemNameDataPtr;
135    UChar bestPattern[20];
136    UChar result[20];
137    int32_t length;
138    UChar *s;
139    const UChar *r;
140
141    dtpg=udatpg_open("fi", &errorCode);
142    if(U_FAILURE(errorCode)) {
143        log_err_status(errorCode, "udatpg_open(fi) failed - %s\n", u_errorName(errorCode));
144        return;
145    }
146    length = udatpg_getBestPattern(dtpg, testSkeleton1, 4,
147                                   bestPattern, 20, &errorCode);
148    if(U_FAILURE(errorCode)) {
149        log_err("udatpg_getBestPattern failed - %s\n", u_errorName(errorCode));
150        return;
151    }
152    if((u_memcmp(bestPattern, expectingBestPattern, length)!=0) || bestPattern[length]!=0) {
153        log_err("udatpg_getBestPattern did not return the expected string\n");
154        return;
155    }
156
157
158    /* Test skeleton == NULL */
159    s=NULL;
160    length = udatpg_getBestPattern(dtpg, s, 0, bestPattern, 20, &errorCode);
161    if(!U_FAILURE(errorCode)&&(length!=0) ) {
162        log_err("udatpg_getBestPattern failed in illegal argument - skeleton is NULL.\n");
163        return;
164    }
165
166    /* Test udatpg_getSkeleton */
167    length = udatpg_getSkeleton(dtpg, testPattern, 5, result, 20,  &errorCode);
168    if(U_FAILURE(errorCode)) {
169        log_err("udatpg_getSkeleton failed - %s\n", u_errorName(errorCode));
170        return;
171    }
172    if((u_memcmp(result, expectingSkeleton, length)!=0) || result[length]!=0) {
173        log_err("udatpg_getSkeleton did not return the expected string\n");
174        return;
175    }
176
177    /* Test pattern == NULL */
178    s=NULL;
179    length = udatpg_getSkeleton(dtpg, s, 0, result, 20, &errorCode);
180    if(!U_FAILURE(errorCode)&&(length!=0) ) {
181        log_err("udatpg_getSkeleton failed in illegal argument - pattern is NULL.\n");
182        return;
183    }
184
185    /* Test udatpg_getBaseSkeleton */
186    length = udatpg_getBaseSkeleton(dtpg, testPattern, 5, result, 20,  &errorCode);
187    if(U_FAILURE(errorCode)) {
188        log_err("udatpg_getBaseSkeleton failed - %s\n", u_errorName(errorCode));
189        return;
190    }
191    if((u_memcmp(result, expectingBaseSkeleton, length)!=0) || result[length]!=0) {
192        log_err("udatpg_getBaseSkeleton did not return the expected string\n");
193        return;
194    }
195
196    /* Test pattern == NULL */
197    s=NULL;
198    length = udatpg_getBaseSkeleton(dtpg, s, 0, result, 20, &errorCode);
199    if(!U_FAILURE(errorCode)&&(length!=0) ) {
200        log_err("udatpg_getBaseSkeleton failed in illegal argument - pattern is NULL.\n");
201        return;
202    }
203
204    /* set append format to {1}{0} */
205    udatpg_setAppendItemFormat( dtpg, UDATPG_MONTH_FIELD, testFormat, 7 );
206    r = udatpg_getAppendItemFormat(dtpg, UDATPG_MONTH_FIELD, &length);
207
208
209    if(length!=7 || 0!=u_memcmp(r, testFormat, length) || r[length]!=0) {
210        log_err("udatpg_setAppendItemFormat did not return the expected string\n");
211        return;
212    }
213
214    for (appItemNameDataPtr = appendItemNameData; appItemNameDataPtr->field <  UDATPG_FIELD_COUNT; appItemNameDataPtr++) {
215        int32_t nameLength;
216        const UChar * namePtr = udatpg_getAppendItemName(dtpg, appItemNameDataPtr->field, &nameLength);
217        if ( namePtr == NULL || u_strncmp(appItemNameDataPtr->name, namePtr, nameLength) != 0 ) {
218            log_err("udatpg_getAppendItemName returns invalid name for field %d\n", (int)appItemNameDataPtr->field);
219        }
220    }
221
222    /* set append name to hr */
223    udatpg_setAppendItemName(dtpg, UDATPG_HOUR_FIELD, appendItemName, 2);
224    r = udatpg_getAppendItemName(dtpg, UDATPG_HOUR_FIELD, &length);
225
226    if(length!=2 || 0!=u_memcmp(r, appendItemName, length) || r[length]!=0) {
227        log_err("udatpg_setAppendItemName did not return the expected string\n");
228        return;
229    }
230
231    /* set date time format to {1}{0} */
232    udatpg_setDateTimeFormat( dtpg, testFormat, 7 );
233    r = udatpg_getDateTimeFormat(dtpg, &length);
234
235    if(length!=7 || 0!=u_memcmp(r, testFormat, length) || r[length]!=0) {
236        log_err("udatpg_setDateTimeFormat did not return the expected string\n");
237        return;
238    }
239    udatpg_close(dtpg);
240}
241
242static void TestBuilder() {
243    UErrorCode errorCode=U_ZERO_ERROR;
244    UDateTimePatternGenerator *dtpg;
245    UDateTimePatternConflict conflict;
246    UEnumeration *en;
247    UChar result[20];
248    int32_t length, pLength;
249    const UChar *s, *p;
250    const UChar* ptrResult[2];
251    int32_t count=0;
252    UDateTimePatternGenerator *generator;
253    int32_t formattedCapacity, resultLen,patternCapacity ;
254    UChar   pattern[40], formatted[40];
255    UDateFormat *formatter;
256    UDate sampleDate = 837039928046.0;
257    static const char locale[]= "fr";
258    UErrorCode status=U_ZERO_ERROR;
259
260    /* test create an empty DateTimePatternGenerator */
261    dtpg=udatpg_openEmpty(&errorCode);
262    if(U_FAILURE(errorCode)) {
263        log_err("udatpg_openEmpty() failed - %s\n", u_errorName(errorCode));
264        return;
265    }
266
267    /* Add a pattern */
268    conflict = udatpg_addPattern(dtpg, redundantPattern, 5, FALSE, result, 20,
269                                 &length, &errorCode);
270    if(U_FAILURE(errorCode)) {
271        log_err("udatpg_addPattern() failed - %s\n", u_errorName(errorCode));
272        return;
273    }
274    /* Add a redundant pattern */
275    conflict = udatpg_addPattern(dtpg, redundantPattern, 5, FALSE, result, 20,
276                                 &length, &errorCode);
277    if(conflict == UDATPG_NO_CONFLICT) {
278        log_err("udatpg_addPattern() failed to find the duplicate pattern.\n");
279        return;
280    }
281    /* Test pattern == NULL */
282    s=NULL;
283    length = udatpg_addPattern(dtpg, s, 0, FALSE, result, 20,
284                               &length, &errorCode);
285    if(!U_FAILURE(errorCode)&&(length!=0) ) {
286        log_err("udatpg_addPattern failed in illegal argument - pattern is NULL.\n");
287        return;
288    }
289
290    /* replace field type */
291    errorCode=U_ZERO_ERROR;
292    conflict = udatpg_addPattern(dtpg, testPattern2, 7, FALSE, result, 20,
293                                 &length, &errorCode);
294    if((conflict != UDATPG_NO_CONFLICT)||U_FAILURE(errorCode)) {
295        log_err("udatpg_addPattern() failed to add HH:mm v. - %s\n", u_errorName(errorCode));
296        return;
297    }
298    length = udatpg_replaceFieldTypes(dtpg, testPattern2, 7, replacedStr, 4,
299                                      result, 20, &errorCode);
300    if (U_FAILURE(errorCode) || (length==0) ) {
301        log_err("udatpg_replaceFieldTypes failed!\n");
302        return;
303    }
304
305    /* Get all skeletons and the crroespong pattern for each skeleton. */
306    ptrResult[0] = testPattern2;
307    ptrResult[1] = redundantPattern;
308    count=0;
309    en = udatpg_openSkeletons(dtpg, &errorCode);
310    if (U_FAILURE(errorCode) || (length==0) ) {
311        log_err("udatpg_openSkeletons failed!\n");
312        return;
313    }
314    while ( (s=uenum_unext(en, &length, &errorCode))!= NULL) {
315        p = udatpg_getPatternForSkeleton(dtpg, s, length, &pLength);
316        if (U_FAILURE(errorCode) || p==NULL || u_memcmp(p, ptrResult[count], pLength)!=0 ) {
317            log_err("udatpg_getPatternForSkeleton failed!\n");
318            return;
319        }
320        count++;
321    }
322    uenum_close(en);
323
324    /* Get all baseSkeletons */
325    en = udatpg_openBaseSkeletons(dtpg, &errorCode);
326    count=0;
327    while ( (s=uenum_unext(en, &length, &errorCode))!= NULL) {
328        p = udatpg_getPatternForSkeleton(dtpg, s, length, &pLength);
329        if (U_FAILURE(errorCode) || p==NULL || u_memcmp(p, resultBaseSkeletons[count], pLength)!=0 ) {
330            log_err("udatpg_getPatternForSkeleton failed!\n");
331            return;
332        }
333        count++;
334    }
335    if (U_FAILURE(errorCode) || (length==0) ) {
336        log_err("udatpg_openSkeletons failed!\n");
337        return;
338    }
339    uenum_close(en);
340
341    udatpg_close(dtpg);
342
343    /* sample code in Userguide */
344    patternCapacity = UPRV_LENGTHOF(pattern);
345    status=U_ZERO_ERROR;
346    generator=udatpg_open(locale, &status);
347    if(U_FAILURE(status)) {
348        return;
349    }
350
351    /* get a pattern for an abbreviated month and day */
352    length = udatpg_getBestPattern(generator, skeleton, 4,
353                                   pattern, patternCapacity, &status);
354    formatter = udat_open(UDAT_PATTERN, UDAT_PATTERN, locale, timeZoneGMT, -1,
355                          pattern, length, &status);
356    if (formatter==NULL) {
357        log_err("Failed to initialize the UDateFormat of the sample code in Userguide.\n");
358        udatpg_close(generator);
359        return;
360    }
361
362    /* use it to format (or parse) */
363    formattedCapacity = UPRV_LENGTHOF(formatted);
364    resultLen=udat_format(formatter, ucal_getNow(), formatted, formattedCapacity,
365                          NULL, &status);
366    /* for French, the result is "13 sept." */
367
368    /* cannot use the result from ucal_getNow() because the value change evreyday. */
369    resultLen=udat_format(formatter, sampleDate, formatted, formattedCapacity,
370                          NULL, &status);
371    if ( u_memcmp(sampleFormatted, formatted, resultLen) != 0 ) {
372        log_err("Failed udat_format() of sample code in Userguide.\n");
373    }
374    udatpg_close(generator);
375    udat_close(formatter);
376}
377
378typedef struct DTPtnGenOptionsData {
379    const char *                    locale;
380    const UChar *                   skel;
381    UDateTimePatternMatchOptions    options;
382    const UChar *                   expectedPattern;
383} DTPtnGenOptionsData;
384enum { kTestOptionsPatLenMax = 32 };
385
386static const UChar skel_Hmm[]     = { 0x0048, 0x006D, 0x006D, 0 };
387static const UChar skel_HHmm[]    = { 0x0048, 0x0048, 0x006D, 0x006D, 0 };
388static const UChar skel_hhmm[]    = { 0x0068, 0x0068, 0x006D, 0x006D, 0 };
389static const UChar patn_hcmm_a[]  = { 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h:mm a */
390static const UChar patn_HHcmm[]   = { 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0 }; /* HH:mm */
391static const UChar patn_hhcmm_a[] = { 0x0068, 0x0068, 0x003A, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh:mm a */
392static const UChar patn_HHpmm[]   = { 0x0048, 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* HH.mm */
393static const UChar patn_hpmm_a[]  = { 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* h.mm a */
394static const UChar patn_Hpmm[]    = { 0x0048, 0x002E, 0x006D, 0x006D, 0 }; /* H.mm */
395static const UChar patn_hhpmm_a[] = { 0x0068, 0x0068, 0x002E, 0x006D, 0x006D, 0x0020, 0x0061, 0 }; /* hh.mm a */
396
397static void TestOptions() {
398    const DTPtnGenOptionsData testData[] = {
399        /*loc   skel       options                       expectedPattern */
400        { "en", skel_Hmm,  UDATPG_MATCH_NO_OPTIONS,        patn_HHcmm   },
401        { "en", skel_HHmm, UDATPG_MATCH_NO_OPTIONS,        patn_HHcmm   },
402        { "en", skel_hhmm, UDATPG_MATCH_NO_OPTIONS,        patn_hcmm_a  },
403        { "en", skel_Hmm,  UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHcmm   },
404        { "en", skel_HHmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHcmm   },
405        { "en", skel_hhmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_hhcmm_a },
406        { "da", skel_Hmm,  UDATPG_MATCH_NO_OPTIONS,        patn_HHpmm   },
407        { "da", skel_HHmm, UDATPG_MATCH_NO_OPTIONS,        patn_HHpmm   },
408        { "da", skel_hhmm, UDATPG_MATCH_NO_OPTIONS,        patn_hpmm_a  },
409        { "da", skel_Hmm,  UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_Hpmm    },
410        { "da", skel_HHmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_HHpmm   },
411        { "da", skel_hhmm, UDATPG_MATCH_HOUR_FIELD_LENGTH, patn_hhpmm_a },
412    };
413
414    int count = UPRV_LENGTHOF(testData);
415    const DTPtnGenOptionsData * testDataPtr = testData;
416
417    for (; count-- > 0; ++testDataPtr) {
418        UErrorCode status = U_ZERO_ERROR;
419        UDateTimePatternGenerator * dtpgen = udatpg_open(testDataPtr->locale, &status);
420        if ( U_SUCCESS(status) ) {
421            UChar pattern[kTestOptionsPatLenMax];
422            int32_t patLen = udatpg_getBestPatternWithOptions(dtpgen, testDataPtr->skel, -1,
423                                                              testDataPtr->options, pattern,
424                                                              kTestOptionsPatLenMax, &status);
425            if ( U_FAILURE(status) || u_strncmp(pattern, testDataPtr->expectedPattern, patLen+1) != 0 ) {
426                char skelBytes[kTestOptionsPatLenMax];
427                char expectedPatternBytes[kTestOptionsPatLenMax];
428                char patternBytes[kTestOptionsPatLenMax];
429                log_err("ERROR udatpg_getBestPatternWithOptions, locale %s, skeleton %s, options 0x%04X, expected pattern %s, got %s, status %d\n",
430                        testDataPtr->locale, u_austrncpy(skelBytes,testDataPtr->skel,kTestOptionsPatLenMax), testDataPtr->options,
431                        u_austrncpy(expectedPatternBytes,testDataPtr->expectedPattern,kTestOptionsPatLenMax),
432                        u_austrncpy(patternBytes,pattern,kTestOptionsPatLenMax), status );
433            }
434            udatpg_close(dtpgen);
435        } else {
436            log_data_err("ERROR udatpg_open failed for locale %s : %s - (Are you missing data?)\n", testDataPtr->locale, myErrorName(status));
437        }
438    }
439}
440
441#endif
442