• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1997-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 /********************************************************************************
9 *
10 * File CDATTST.C
11 *
12 * Modification History:
13 *        Name                     Description
14 *     Madhu Katragadda               Creation
15 *********************************************************************************
16 */
17 
18 /* C API TEST FOR DATE FORMAT */
19 
20 #include "unicode/utypes.h"
21 
22 #if !UCONFIG_NO_FORMATTING
23 
24 #include "unicode/uloc.h"
25 #include "unicode/udat.h"
26 #include "unicode/udatpg.h"
27 #include "unicode/ucal.h"
28 #include "unicode/unum.h"
29 #include "unicode/ustring.h"
30 #include "unicode/ufieldpositer.h"
31 #include "cintltst.h"
32 #include "cdattst.h"
33 #include "cformtst.h"
34 #include "cstring.h"
35 #include "cmemory.h"
36 
37 #include <math.h>
38 #include <stdbool.h>
39 #include <stdio.h> // for sprintf()
40 
41 static void TestExtremeDates(void);
42 static void TestAllLocales(void);
43 static void TestRelativeCrash(void);
44 static void TestContext(void);
45 static void TestCalendarDateParse(void);
46 static void TestParseErrorReturnValue(void);
47 static void TestFormatForFields(void);
48 static void TestForceGannenNumbering(void);
49 static void TestMapDateToCalFields(void);
50 static void TestNarrowQuarters(void);
51 static void TestExtraneousCharacters(void);
52 static void TestParseTooStrict(void);
53 static void TestHourCycle(void);
54 static void TestLocaleNameCrash(void);
55 
56 void addDateForTest(TestNode** root);
57 
58 #define TESTCASE(x) addTest(root, &x, "tsformat/cdattst/" #x)
59 
addDateForTest(TestNode ** root)60 void addDateForTest(TestNode** root)
61 {
62     TESTCASE(TestDateFormat);
63     TESTCASE(TestRelativeDateFormat);
64     TESTCASE(TestSymbols);
65     TESTCASE(TestDateFormatCalendar);
66     TESTCASE(TestExtremeDates);
67     TESTCASE(TestAllLocales);
68     TESTCASE(TestRelativeCrash);
69     TESTCASE(TestContext);
70     TESTCASE(TestCalendarDateParse);
71     TESTCASE(TestOverrideNumberFormat);
72     TESTCASE(TestParseErrorReturnValue);
73     TESTCASE(TestFormatForFields);
74     TESTCASE(TestForceGannenNumbering);
75     TESTCASE(TestMapDateToCalFields);
76     TESTCASE(TestNarrowQuarters);
77     TESTCASE(TestExtraneousCharacters);
78     TESTCASE(TestParseTooStrict);
79     TESTCASE(TestHourCycle);
80     TESTCASE(TestLocaleNameCrash);
81 }
82 /* Testing the DateFormat API */
TestDateFormat(void)83 static void TestDateFormat(void)
84 {
85     UDateFormat *def, *fr, *it, *de, *def1, *fr_pat;
86     UDateFormat *any;
87     UDateFormat *copy;
88     UErrorCode status = U_ZERO_ERROR;
89     UChar* result = NULL;
90     const UCalendar *cal;
91     const UNumberFormat *numformat1, *numformat2;
92     UNumberFormat *adoptNF;
93     UChar temp[80];
94     int32_t numlocales;
95     UDate d1;
96     int i;
97     int32_t resultlength;
98     int32_t resultlengthneeded;
99     int32_t parsepos;
100     UDate d = 837039928046.0;
101     double num = -10456.37;
102     /*const char* str="yyyy.MM.dd G 'at' hh:mm:ss z";
103     const char t[]="2/3/76 2:50 AM";*/
104     /*Testing udat_open() to open a dateformat */
105 
106     ctest_setTimeZone(NULL, &status);
107 
108     log_verbose("\nTesting udat_open() with various parameters\n");
109     fr = udat_open(UDAT_FULL, UDAT_DEFAULT, "fr_FR", NULL,0, NULL, 0,&status);
110     if(U_FAILURE(status))
111     {
112         log_data_err("FAIL: error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
113             myErrorName(status) );
114         return;
115     }
116     /* this is supposed to open default date format, but later on it treats it like it is "en_US"
117        - very bad if you try to run the tests on machine where default locale is NOT "en_US" */
118     /* def = udat_open(UDAT_SHORT, UDAT_SHORT, NULL, NULL, 0, &status); */
119     def = udat_open(UDAT_SHORT, UDAT_SHORT, "en_US", NULL, 0,NULL, 0, &status);
120     if(U_FAILURE(status))
121     {
122         log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
123             myErrorName(status) );
124         return;
125     }
126     it = udat_open(UDAT_DEFAULT, UDAT_MEDIUM, "it_IT", NULL, 0, NULL, 0,&status);
127     if(U_FAILURE(status))
128     {
129         log_err("FAIL: error in creating the dateformat using medium date style with italian locale\n %s\n",
130             myErrorName(status) );
131         return;
132     }
133     de = udat_open(UDAT_LONG, UDAT_LONG, "de_DE", NULL, 0, NULL, 0,&status);
134     if(U_FAILURE(status))
135     {
136         log_err("FAIL: error in creating the dateformat using long time and date styles with german locale\n %s\n",
137             myErrorName(status));
138         return;
139     }
140     /*creating a default dateformat */
141     def1 = udat_open(UDAT_SHORT, UDAT_SHORT, NULL, NULL, 0,NULL, 0, &status);
142     if(U_FAILURE(status))
143     {
144         log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
145             myErrorName(status) );
146         return;
147     }
148 
149 
150     /*Testing udat_getAvailable() and udat_countAvailable()*/
151     log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
152     numlocales=udat_countAvailable();
153     /* use something sensible w/o hardcoding the count */
154     if(numlocales < 0)
155         log_data_err("FAIL: error in countAvailable\n");
156     log_verbose("The number of locales for which date/time formatting patterns are available is %d\n", numlocales);
157 
158     for(i=0;i<numlocales;i++) {
159       UErrorCode subStatus = U_ZERO_ERROR;
160       log_verbose("Testing open of %s\n", udat_getAvailable(i));
161       any = udat_open(UDAT_SHORT, UDAT_SHORT, udat_getAvailable(i), NULL ,0, NULL, 0, &subStatus);
162       if(U_FAILURE(subStatus)) {
163         log_data_err("FAIL: date format %s (getAvailable(%d)) is not instantiable: %s\n", udat_getAvailable(i), i, u_errorName(subStatus));
164       }
165       udat_close(any);
166     }
167 
168     /*Testing udat_clone()*/
169     log_verbose("\nTesting the udat_clone() function of date format\n");
170     copy=udat_clone(def, &status);
171     if(U_FAILURE(status)){
172         log_err("Error in creating the clone using udat_clone: %s\n", myErrorName(status) );
173     }
174     /*if(def != copy)
175         log_err("Error in udat_clone");*/ /*how should i check for equality???? */
176 
177     /*Testing udat_format()*/
178     log_verbose("\nTesting the udat_format() function of date format\n");
179     u_strcpy(temp, u"7/10/96, 4:05\u202FPM");
180     /*format using def */
181     resultlength=0;
182     resultlengthneeded=udat_format(def, d, NULL, resultlength, NULL, &status);
183     if(status==U_BUFFER_OVERFLOW_ERROR)
184     {
185         status=U_ZERO_ERROR;
186         resultlength=resultlengthneeded+1;
187         if(result != NULL) {
188             free(result);
189             result = NULL;
190         }
191         result=(UChar*)malloc(sizeof(UChar) * resultlength);
192         udat_format(def, d, result, resultlength, NULL, &status);
193     }
194     if(U_FAILURE(status) || !result)
195     {
196         log_err("FAIL: Error in formatting using udat_format(.....) %s\n", myErrorName(status) );
197         return;
198     }
199     else
200         log_verbose("PASS: formatting successful\n");
201     if(u_strcmp(result, temp)==0)
202         log_verbose("PASS: Date Format for US locale successful using udat_format()\n");
203     else {
204         char xbuf[2048];
205         char gbuf[2048];
206         u_austrcpy(xbuf, temp);
207         u_austrcpy(gbuf, result);
208         log_err("FAIL: Date Format for US locale failed using udat_format() - expected %s got %s\n", xbuf, gbuf);
209     }
210     /*format using fr */
211 
212     u_unescape("10 juil. 1996, 16:05:28 heure d\\u2019\\u00E9t\\u00E9 du Pacifique nord-am\\u00E9ricain", temp, 80);
213     if(result != NULL) {
214         free(result);
215         result = NULL;
216     }
217     result=myDateFormat(fr, d);
218     if(u_strcmp(result, temp)==0) {
219         log_verbose("PASS: Date Format for french locale successful using udat_format()\n");
220     } else {
221         char xbuf[2048];
222         char gbuf[2048];
223         u_austrcpy(xbuf, temp);
224         u_austrcpy(gbuf, result);
225         log_data_err("FAIL: Date Format for french locale failed using udat_format() - expected %s got %s\n", xbuf, gbuf);
226     }
227 
228     /*format using it */
229     u_uastrcpy(temp, "10 lug 1996, 16:05:28");
230 
231     {
232         UChar *fmtted;
233         char g[100];
234         char x[100];
235 
236         fmtted = myDateFormat(it,d);
237         u_austrcpy(g, fmtted);
238         u_austrcpy(x, temp);
239         if(u_strcmp(fmtted, temp)==0) {
240             log_verbose("PASS: Date Format for italian locale successful uisng udat_format() - wanted %s, got %s\n", x, g);
241         } else {
242             log_data_err("FAIL: Date Format for italian locale failed using udat_format() - wanted %s, got %s\n", x, g);
243         }
244     }
245 
246     /*Testing parsing using udat_parse()*/
247     log_verbose("\nTesting parsing using udat_parse()\n");
248     u_strcpy(temp, u"2/3/76, 2:50\u202FAM");
249     parsepos=0;
250     status=U_ZERO_ERROR;
251 
252     d1=udat_parse(def, temp, u_strlen(temp), &parsepos, &status);
253     if(U_FAILURE(status))
254     {
255         log_err("FAIL: Error in parsing using udat_parse(.....) %s\n", myErrorName(status) );
256     }
257     else
258         log_verbose("PASS: parsing successful\n");
259     /*format it back and check for equality */
260 
261 
262     if(u_strcmp(myDateFormat(def, d1),temp)!=0)
263         log_err("FAIL: error in parsing\n");
264 
265     /*Testing parsing using udat_parse()*/
266     log_verbose("\nTesting parsing using udat_parse()\n");
267     u_uastrcpy(temp,"2/Don't parse this part");
268     status=U_ZERO_ERROR;
269 
270     d1=udat_parse(def, temp, u_strlen(temp), NULL, &status);
271     if(status != U_PARSE_ERROR)
272     {
273         log_err("FAIL: udat_parse(\"bad string\") passed when it should have failed\n");
274     }
275     else
276         log_verbose("PASS: parsing successful\n");
277 
278 
279 
280     /*Testing udat_openPattern()  */
281     status=U_ZERO_ERROR;
282     log_verbose("\nTesting the udat_openPattern with a specified pattern\n");
283     /*for french locale */
284     fr_pat=udat_open(UDAT_PATTERN, UDAT_PATTERN,"fr_FR",NULL,0,temp, u_strlen(temp), &status);
285     if(U_FAILURE(status))
286     {
287         log_err("FAIL: Error in creating a date format using udat_openPattern \n %s\n",
288             myErrorName(status) );
289     }
290     else
291         log_verbose("PASS: creating dateformat using udat_openPattern() successful\n");
292 
293 
294         /*Testing applyPattern and toPattern */
295     log_verbose("\nTesting applyPattern and toPattern()\n");
296     udat_applyPattern(def1, false, temp, u_strlen(temp));
297     log_verbose("Extracting the pattern\n");
298 
299     resultlength=0;
300     resultlengthneeded=udat_toPattern(def1, false, NULL, resultlength, &status);
301     if(status==U_BUFFER_OVERFLOW_ERROR)
302     {
303         status=U_ZERO_ERROR;
304         resultlength=resultlengthneeded + 1;
305         result=(UChar*)malloc(sizeof(UChar) * resultlength);
306         udat_toPattern(def1, false, result, resultlength, &status);
307     }
308     if(U_FAILURE(status))
309     {
310         log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
311             myErrorName(status) );
312     }
313     if(u_strcmp(result, temp)!=0)
314         log_err("FAIL: Error in extracting the pattern\n");
315     else
316         log_verbose("PASS: applyPattern and toPattern work fine\n");
317 
318     if(result != NULL) {
319         free(result);
320         result = NULL;
321     }
322 
323 
324     /*Testing getter and setter functions*/
325     /*isLenient and setLenient()*/
326     log_verbose("\nTesting the isLenient and setLenient properties\n");
327     udat_setLenient(fr, udat_isLenient(it));
328     if(udat_isLenient(fr) != udat_isLenient(it))
329         log_err("ERROR: setLenient() failed\n");
330     else
331         log_verbose("PASS: setLenient() successful\n");
332 
333 
334     /*Test get2DigitYearStart set2DigitYearStart */
335     log_verbose("\nTesting the get and set 2DigitYearStart properties\n");
336     d1= udat_get2DigitYearStart(fr_pat,&status);
337     if(U_FAILURE(status)) {
338             log_err("ERROR: udat_get2DigitYearStart failed %s\n", myErrorName(status) );
339     }
340     status = U_ZERO_ERROR;
341     udat_set2DigitYearStart(def1 ,d1, &status);
342     if(U_FAILURE(status)) {
343         log_err("ERROR: udat_set2DigitYearStart failed %s\n", myErrorName(status) );
344     }
345     if(udat_get2DigitYearStart(fr_pat, &status) != udat_get2DigitYearStart(def1, &status))
346         log_err("FAIL: error in set2DigitYearStart\n");
347     else
348         log_verbose("PASS: set2DigitYearStart successful\n");
349     /*try setting it to another value */
350     udat_set2DigitYearStart(de, 2000.0, &status);
351     if(U_FAILURE(status)){
352         log_verbose("ERROR: udat_set2DigitYearStart failed %s\n", myErrorName(status) );
353     }
354     if(udat_get2DigitYearStart(de, &status) != 2000)
355         log_err("FAIL: error in set2DigitYearStart\n");
356     else
357         log_verbose("PASS: set2DigitYearStart successful\n");
358 
359 
360 
361     /*Test getNumberFormat() and setNumberFormat() */
362     log_verbose("\nTesting the get and set NumberFormat properties of date format\n");
363     numformat1=udat_getNumberFormat(fr_pat);
364     udat_setNumberFormat(def1, numformat1);
365     numformat2=udat_getNumberFormat(def1);
366     if(u_strcmp(myNumformat(numformat1, num), myNumformat(numformat2, num)) !=0)
367         log_err("FAIL: error in setNumberFormat or getNumberFormat()\n");
368     else
369         log_verbose("PASS:setNumberFormat and getNumberFormat successful\n");
370 
371     /*Test getNumberFormat() and adoptNumberFormat() */
372     log_verbose("\nTesting the get and adopt NumberFormat properties of date format\n");
373     adoptNF= unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
374     udat_adoptNumberFormat(def1, adoptNF);
375     numformat2=udat_getNumberFormat(def1);
376     if(u_strcmp(myNumformat(adoptNF, num), myNumformat(numformat2, num)) !=0)
377         log_err("FAIL: error in adoptNumberFormat or getNumberFormat()\n");
378     else
379         log_verbose("PASS:adoptNumberFormat and getNumberFormat successful\n");
380 
381     /*try setting the number format to another format */
382     numformat1=udat_getNumberFormat(def);
383     udat_setNumberFormat(def1, numformat1);
384     numformat2=udat_getNumberFormat(def1);
385     if(u_strcmp(myNumformat(numformat1, num), myNumformat(numformat2, num)) !=0)
386         log_err("FAIL: error in setNumberFormat or getNumberFormat()\n");
387     else
388         log_verbose("PASS: setNumberFormat and getNumberFormat successful\n");
389 
390 
391 
392     /*Test getCalendar and setCalendar*/
393     log_verbose("\nTesting the udat_getCalendar() and udat_setCalendar() properties\n");
394     cal=udat_getCalendar(fr_pat);
395 
396 
397     udat_setCalendar(def1, cal);
398     if(!ucal_equivalentTo(udat_getCalendar(fr_pat), udat_getCalendar(def1)))
399         log_err("FAIL: Error in setting and getting the calendar\n");
400     else
401         log_verbose("PASS: getting and setting calendar successful\n");
402 
403     if(result!=NULL) {
404         free(result);
405     }
406 
407     /*Closing the UDateForamt */
408     udat_close(def);
409     udat_close(fr);
410     udat_close(it);
411     udat_close(de);
412     udat_close(def1);
413     udat_close(fr_pat);
414     udat_close(copy);
415 
416     ctest_resetTimeZone();
417 }
418 
419 /*
420 Test combined relative date formatting (relative date + non-relative time).
421 This is a bit tricky since we can't have static test data for comparison, the
422 relative date formatting is relative to the time the tests are run. We generate
423 the data for comparison dynamically. However, the tests could fail if they are
424 run right at midnight Pacific time and the call to ucal_getNow() is before midnight
425 while the calls to udat_format are after midnight or span midnight.
426 */
427 static const UDate dayInterval = 24.0*60.0*60.0*1000.0;
428 static const UChar trdfZone[] = { 0x0055, 0x0053, 0x002F, 0x0050, 0x0061, 0x0063, 0x0069, 0x0066, 0x0069, 0x0063, 0 }; /* US/Pacific */
429 static const char trdfLocale[] = "en_US";
430 static const UChar minutesPatn[] = { 0x006D, 0x006D, 0 }; /* "mm" */
431 static const UChar monthLongPatn[] = { 0x004D, 0x004D, 0x004D, 0x004D, 0 }; /* "MMMM" */
432 static const UChar monthMediumPatn[] = { 0x004D, 0x004D, 0x004D, 0 }; /* "MMM" */
433 static const UChar monthShortPatn[] = { 0x004D, 0 }; /* "M" */
434 static const UDateFormatStyle dateStylesList[] = { UDAT_FULL, UDAT_LONG, UDAT_MEDIUM, UDAT_SHORT, UDAT_NONE };
435 static const UChar *monthPatnsList[] = { monthLongPatn, monthLongPatn, monthMediumPatn, monthShortPatn, NULL };
436 static const UChar newTimePatn[] = { 0x0048, 0x0048, 0x002C, 0x006D, 0x006D, 0 }; /* "HH,mm" */
437 static const UChar minutesStr[] = { 0x0034, 0x0039, 0 }; /* "49", minutes string to search for in output */
438 enum { kDateOrTimeOutMax = 96, kDateAndTimeOutMax = 192 };
439 
440 static const UDate minutesTolerance = 2 * 60.0 * 1000.0;
441 static const UDate daysTolerance = 2 * 24.0 * 60.0 * 60.0 * 1000.0;
442 
TestRelativeDateFormat(void)443 static void TestRelativeDateFormat(void)
444 {
445     UDate today = 0.0;
446     const UDateFormatStyle * stylePtr;
447     const UChar ** monthPtnPtr;
448     UErrorCode status = U_ZERO_ERROR;
449     UCalendar * ucal = ucal_open(trdfZone, -1, trdfLocale, UCAL_GREGORIAN, &status);
450     if ( U_SUCCESS(status) ) {
451         int32_t    year, month, day;
452         ucal_setMillis(ucal, ucal_getNow(), &status);
453         year = ucal_get(ucal, UCAL_YEAR, &status);
454         month = ucal_get(ucal, UCAL_MONTH, &status);
455         day = ucal_get(ucal, UCAL_DATE, &status);
456         ucal_setDateTime(ucal, year, month, day, 18, 49, 0, &status); /* set to today at 18:49:00 */
457         today = ucal_getMillis(ucal, &status);
458         ucal_close(ucal);
459     }
460     if ( U_FAILURE(status) || today == 0.0 ) {
461         log_data_err("Generate UDate for a specified time today fails, error %s - (Are you missing data?)\n", myErrorName(status) );
462         return;
463     }
464     for (stylePtr = dateStylesList, monthPtnPtr = monthPatnsList; *stylePtr != UDAT_NONE; ++stylePtr, ++monthPtnPtr) {
465         UDateFormat* fmtRelDateTime;
466         UDateFormat* fmtRelDate;
467         UDateFormat* fmtTime;
468         int32_t dayOffset, limit;
469         UFieldPosition fp;
470         UChar   strDateTime[kDateAndTimeOutMax];
471         UChar   strDate[kDateOrTimeOutMax];
472         UChar   strTime[kDateOrTimeOutMax];
473         UChar * strPtr;
474         int32_t dtpatLen;
475 
476         fmtRelDateTime = udat_open(UDAT_SHORT, *stylePtr | UDAT_RELATIVE, trdfLocale, trdfZone, -1, NULL, 0, &status);
477         if ( U_FAILURE(status) ) {
478             log_data_err("udat_open timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s (Are you missing data?)\n", *stylePtr, myErrorName(status) );
479             continue;
480         }
481         fmtRelDate = udat_open(UDAT_NONE, *stylePtr | UDAT_RELATIVE, trdfLocale, trdfZone, -1, NULL, 0, &status);
482         if ( U_FAILURE(status) ) {
483             log_err("udat_open timeStyle NONE dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
484             udat_close(fmtRelDateTime);
485             continue;
486         }
487         fmtTime = udat_open(UDAT_SHORT, UDAT_NONE, trdfLocale, trdfZone, -1, NULL, 0, &status);
488         if ( U_FAILURE(status) ) {
489             log_err("udat_open timeStyle SHORT dateStyle NONE fails, error %s\n", myErrorName(status) );
490             udat_close(fmtRelDateTime);
491             udat_close(fmtRelDate);
492             continue;
493         }
494 
495         dtpatLen = udat_toPatternRelativeDate(fmtRelDateTime, strDate, kDateAndTimeOutMax, &status);
496         if ( U_FAILURE(status) ) {
497             log_err("udat_toPatternRelativeDate timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
498             status = U_ZERO_ERROR;
499         } else if ( u_strstr(strDate, *monthPtnPtr) == NULL || dtpatLen != u_strlen(strDate) ) {
500             log_err("udat_toPatternRelativeDate timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) date pattern incorrect\n", *stylePtr );
501         }
502         dtpatLen = udat_toPatternRelativeTime(fmtRelDateTime, strTime, kDateAndTimeOutMax, &status);
503         if ( U_FAILURE(status) ) {
504             log_err("udat_toPatternRelativeTime timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
505             status = U_ZERO_ERROR;
506         } else if ( u_strstr(strTime, minutesPatn) == NULL || dtpatLen != u_strlen(strTime) ) {
507             log_err("udat_toPatternRelativeTime timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) time pattern incorrect\n", *stylePtr );
508         }
509         dtpatLen = udat_toPattern(fmtRelDateTime, false, strDateTime, kDateAndTimeOutMax, &status);
510         if ( U_FAILURE(status) ) {
511             log_err("udat_toPattern timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
512             status = U_ZERO_ERROR;
513         } else if ( u_strstr(strDateTime, strDate) == NULL || u_strstr(strDateTime, strTime) == NULL || dtpatLen != u_strlen(strDateTime) ) {
514             log_err("udat_toPattern timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) dateTime pattern incorrect\n", *stylePtr );
515         }
516         udat_applyPatternRelative(fmtRelDateTime, strDate, u_strlen(strDate), newTimePatn, u_strlen(newTimePatn), &status);
517         if ( U_FAILURE(status) ) {
518             log_err("udat_applyPatternRelative timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
519             status = U_ZERO_ERROR;
520         } else {
521             udat_toPattern(fmtRelDateTime, false, strDateTime, kDateAndTimeOutMax, &status);
522             if ( U_FAILURE(status) ) {
523                 log_err("udat_toPattern timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
524                 status = U_ZERO_ERROR;
525             } else if ( u_strstr(strDateTime, newTimePatn) == NULL ) {
526                 log_err("udat_applyPatternRelative timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) didn't update time pattern\n", *stylePtr );
527             }
528         }
529         udat_applyPatternRelative(fmtRelDateTime, strDate, u_strlen(strDate), strTime, u_strlen(strTime), &status); /* restore original */
530 
531         fp.field = UDAT_MINUTE_FIELD;
532         for (dayOffset = -2, limit = 2; dayOffset <= limit; ++dayOffset) {
533             UDate   dateToUse = today + (float)dayOffset*dayInterval;
534 
535             udat_format(fmtRelDateTime, dateToUse, strDateTime, kDateAndTimeOutMax, &fp, &status);
536             if ( U_FAILURE(status) ) {
537                 log_err("udat_format timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
538                 status = U_ZERO_ERROR;
539             } else {
540                 int32_t parsePos = 0;
541                 UDate dateResult = udat_parse(fmtRelDateTime, strDateTime, -1, &parsePos, &status);
542                 UDate dateDiff =  (dateResult >= dateToUse)? dateResult - dateToUse: dateToUse - dateResult;
543                 if ( U_FAILURE(status) || dateDiff > minutesTolerance ) {
544                     log_err("udat_parse timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s, expect approx %.1f, got %.1f, parsePos %d\n",
545                             *stylePtr, myErrorName(status), dateToUse, dateResult, parsePos );
546                     status = U_ZERO_ERROR;
547                 }
548 
549                 udat_format(fmtRelDate, dateToUse, strDate, kDateOrTimeOutMax, NULL, &status);
550                 if ( U_FAILURE(status) ) {
551                     log_err("udat_format timeStyle NONE dateStyle (%d | UDAT_RELATIVE) fails, error %s\n", *stylePtr, myErrorName(status) );
552                     status = U_ZERO_ERROR;
553                 } else if ( u_strstr(strDateTime, strDate) == NULL ) {
554                     log_err("relative date string not found in udat_format timeStyle SHORT dateStyle (%d | UDAT_RELATIVE)\n", *stylePtr );
555                 } else {
556                     parsePos = 0;
557                     dateResult = udat_parse(fmtRelDate, strDate, -1, &parsePos, &status);
558                     dateDiff =  (dateResult >= dateToUse)? dateResult - dateToUse: dateToUse - dateResult;
559                     if ( U_FAILURE(status) || dateDiff > daysTolerance ) {
560                         log_err("udat_parse timeStyle NONE dateStyle (%d | UDAT_RELATIVE) fails, error %s, expect approx %.1f, got %.1f, parsePos %d\n",
561                                 *stylePtr, myErrorName(status), dateToUse, dateResult, parsePos );
562                         status = U_ZERO_ERROR;
563                     }
564                 }
565 
566                 udat_format(fmtTime, dateToUse, strTime, kDateOrTimeOutMax, NULL, &status);
567                 if ( U_FAILURE(status) ) {
568                     log_err("udat_format timeStyle SHORT dateStyle NONE fails, error %s\n", myErrorName(status) );
569                     status = U_ZERO_ERROR;
570                 } else if ( u_strstr(strDateTime, strTime) == NULL ) {
571                     log_err("time string not found in udat_format timeStyle SHORT dateStyle (%d | UDAT_RELATIVE)\n", *stylePtr );
572                 }
573 
574                 strPtr = u_strstr(strDateTime, minutesStr);
575                 if ( strPtr != NULL ) {
576                     int32_t beginIndex = (int32_t)(strPtr - strDateTime);
577                     if ( fp.beginIndex != beginIndex ) {
578                         log_err("UFieldPosition beginIndex %d, expected %d, in udat_format timeStyle SHORT dateStyle (%d | UDAT_RELATIVE)\n", fp.beginIndex, beginIndex, *stylePtr );
579                     }
580                 } else {
581                     log_err("minutes string not found in udat_format timeStyle SHORT dateStyle (%d | UDAT_RELATIVE)\n", *stylePtr );
582                 }
583             }
584         }
585 
586         udat_close(fmtRelDateTime);
587         udat_close(fmtRelDate);
588         udat_close(fmtTime);
589      }
590 }
591 
592 /*Testing udat_getSymbols() and udat_setSymbols() and udat_countSymbols()*/
TestSymbols(void)593 static void TestSymbols(void)
594 {
595     UDateFormat *def, *fr, *zhChiCal, *esMX;
596     UErrorCode status = U_ZERO_ERROR;
597     UChar *value=NULL;
598     UChar *result = NULL;
599     int32_t resultlength;
600     int32_t resultlengthout;
601     UChar *pattern;
602 
603 
604     /*creating a dateformat with french locale */
605     log_verbose("\ncreating a date format with french locale\n");
606     fr = udat_open(UDAT_FULL, UDAT_DEFAULT, "fr_FR", NULL, 0, NULL, 0, &status);
607     if(U_FAILURE(status))
608     {
609         log_data_err("error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
610             myErrorName(status) );
611         return;
612     }
613     /*creating a default dateformat */
614     log_verbose("\ncreating a date format with default locale\n");
615     /* this is supposed to open default date format, but later on it treats it like it is "en_US"
616        - very bad if you try to run the tests on machine where default locale is NOT "en_US" */
617     /* def = udat_open(UDAT_DEFAULT,UDAT_DEFAULT ,NULL, NULL, 0, &status); */
618     def = udat_open(UDAT_DEFAULT,UDAT_DEFAULT ,"en_US", NULL, 0, NULL, 0, &status);
619     if(U_FAILURE(status))
620     {
621         log_err("error in creating the dateformat using short date and time style\n %s\n",
622             myErrorName(status) );
623         return;
624     }
625     /*creating a dateformat with zh locale */
626     log_verbose("\ncreating a date format with zh locale for chinese calendar\n");
627     zhChiCal = udat_open(UDAT_NONE, UDAT_FULL, "zh@calendar=chinese", NULL, 0, NULL, 0, &status);
628     if(U_FAILURE(status))
629     {
630         log_data_err("error in creating the dateformat using full date, no time, locale zh@calendar=chinese -> %s (Are you missing data?)\n",
631             myErrorName(status) );
632         return;
633     }
634     /*creating a dateformat with es_MX locale */
635     log_verbose("\ncreating a date format with es_MX locale\n");
636     esMX = udat_open(UDAT_SHORT, UDAT_NONE, "es_MX", NULL, 0, NULL, 0, &status);
637     if(U_FAILURE(status))
638     {
639         log_data_err("error in creating the dateformat using no date, short time, locale es_MX -> %s (Are you missing data?)\n",
640             myErrorName(status) );
641         return;
642     }
643 
644     /*Testing countSymbols, getSymbols and setSymbols*/
645     log_verbose("\nTesting countSymbols\n");
646     /*since the month names has the last string empty and week names are 1 based 1.e first string in the weeknames array is empty */
647     if(udat_countSymbols(def, UDAT_ERAS)!=2 || udat_countSymbols(def, UDAT_MONTHS)!=12 ||
648         udat_countSymbols(def, UDAT_SHORT_MONTHS)!=12 || udat_countSymbols(def, UDAT_WEEKDAYS)!=8 ||
649         udat_countSymbols(def, UDAT_SHORT_WEEKDAYS)!=8 || udat_countSymbols(def, UDAT_AM_PMS)!=2 ||
650         udat_countSymbols(def, UDAT_QUARTERS) != 4 || udat_countSymbols(def, UDAT_SHORT_QUARTERS) != 4 ||
651         udat_countSymbols(def, UDAT_LOCALIZED_CHARS)!=1 || udat_countSymbols(def, UDAT_SHORTER_WEEKDAYS)!=8 ||
652         udat_countSymbols(zhChiCal, UDAT_CYCLIC_YEARS_NARROW)!=60 || udat_countSymbols(zhChiCal, UDAT_ZODIAC_NAMES_NARROW)!=12)
653     {
654         log_err("FAIL: error in udat_countSymbols\n");
655     }
656     else
657         log_verbose("PASS: udat_countSymbols() successful\n");
658 
659     /*testing getSymbols*/
660     log_verbose("\nTesting getSymbols\n");
661     pattern=(UChar*)malloc(sizeof(UChar) * 10);
662     u_uastrcpy(pattern, "jeudi");
663     resultlength=0;
664     resultlengthout=udat_getSymbols(fr, UDAT_WEEKDAYS, 5 , NULL, resultlength, &status);
665     if(status==U_BUFFER_OVERFLOW_ERROR)
666     {
667         status=U_ZERO_ERROR;
668         resultlength=resultlengthout+1;
669         if(result != NULL) {
670             free(result);
671             result = NULL;
672         }
673         result=(UChar*)malloc(sizeof(UChar) * resultlength);
674         udat_getSymbols(fr, UDAT_WEEKDAYS, 5, result, resultlength, &status);
675 
676     }
677     if(U_FAILURE(status))
678     {
679         log_err("FAIL: Error in udat_getSymbols().... %s\n", myErrorName(status) );
680     }
681     else
682         log_verbose("PASS: getSymbols successful\n");
683 
684     if(u_strcmp(result, pattern)==0)
685         log_verbose("PASS: getSymbols retrieved the right value\n");
686     else
687         log_data_err("FAIL: getSymbols retrieved the wrong value\n");
688 
689     /*run series of tests to test getsymbols regressively*/
690     log_verbose("\nTesting getSymbols() regressively\n");
691     VerifygetSymbols(fr, UDAT_WEEKDAYS, 1, "dimanche");
692     VerifygetSymbols(def, UDAT_WEEKDAYS, 1, "Sunday");
693     VerifygetSymbols(fr, UDAT_SHORT_WEEKDAYS, 7, "sam.");
694     VerifygetSymbols(fr, UDAT_SHORTER_WEEKDAYS, 7, "sa");
695     VerifygetSymbols(def, UDAT_SHORT_WEEKDAYS, 7, "Sat");
696     VerifygetSymbols(def, UDAT_MONTHS, 11, "December");
697     VerifygetSymbols(def, UDAT_MONTHS, 0, "January");
698     VerifygetSymbols(fr, UDAT_ERAS, 0, "av. J.-C.");
699     VerifygetSymbols(def, UDAT_AM_PMS, 0, "AM");
700     VerifygetSymbols(def, UDAT_AM_PMS, 1, "PM");
701     VerifygetSymbols(fr, UDAT_SHORT_MONTHS, 0, "janv.");
702     VerifygetSymbols(def, UDAT_SHORT_MONTHS, 11, "Dec");
703     VerifygetSymbols(fr, UDAT_QUARTERS, 0, "1er trimestre");
704     VerifygetSymbols(def, UDAT_QUARTERS, 3, "4th quarter");
705     VerifygetSymbols(fr, UDAT_SHORT_QUARTERS, 1, "T2");
706     VerifygetSymbols(def, UDAT_SHORT_QUARTERS, 2, "Q3");
707     VerifygetSymbols(esMX, UDAT_STANDALONE_NARROW_QUARTERS, 1, "2");
708     VerifygetSymbols(def, UDAT_NARROW_QUARTERS, 2, "3");
709     VerifygetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_ABBREVIATED, 0, "\\u7532\\u5B50");
710     VerifygetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_NARROW, 59, "\\u7678\\u4EA5");
711     VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 0, "\\u9F20");
712     VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_WIDE, 11, "\\u732A");
713 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
714     VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:");
715 #else
716     VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB");
717 #endif
718 
719 
720     if(result != NULL) {
721         free(result);
722         result = NULL;
723     }
724 free(pattern);
725 
726     log_verbose("\nTesting setSymbols\n");
727     /*applying the pattern so that setSymbolss works */
728     resultlength=0;
729     resultlengthout=udat_toPattern(fr, false, NULL, resultlength, &status);
730     if(status==U_BUFFER_OVERFLOW_ERROR)
731     {
732         status=U_ZERO_ERROR;
733         resultlength=resultlengthout + 1;
734         pattern=(UChar*)malloc(sizeof(UChar) * resultlength);
735         udat_toPattern(fr, false, pattern, resultlength, &status);
736     }
737     if(U_FAILURE(status))
738     {
739         log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
740             myErrorName(status) );
741     }
742 
743     udat_applyPattern(def, false, pattern, u_strlen(pattern));
744     resultlength=0;
745     resultlengthout=udat_toPattern(def, false, NULL, resultlength,&status);
746     if(status==U_BUFFER_OVERFLOW_ERROR)
747     {
748         status=U_ZERO_ERROR;
749         resultlength=resultlengthout + 1;
750         if(result != NULL) {
751             free(result);
752             result = NULL;
753         }
754         result=(UChar*)malloc(sizeof(UChar) * resultlength);
755         udat_toPattern(fr, false,result, resultlength, &status);
756     }
757     if(U_FAILURE(status))
758     {
759         log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
760             myErrorName(status) );
761     }
762     if(u_strcmp(result, pattern)==0)
763         log_verbose("Pattern applied properly\n");
764     else
765         log_err("pattern could not be applied properly\n");
766 
767 free(pattern);
768     /*testing set symbols */
769     resultlength=0;
770     resultlengthout=udat_getSymbols(fr, UDAT_MONTHS, 11 , NULL, resultlength, &status);
771     if(status==U_BUFFER_OVERFLOW_ERROR){
772         status=U_ZERO_ERROR;
773         resultlength=resultlengthout+1;
774         if(result != NULL) {
775             free(result);
776             result = NULL;
777         }
778         result=(UChar*)malloc(sizeof(UChar) * resultlength);
779         udat_getSymbols(fr, UDAT_MONTHS, 11, result, resultlength, &status);
780 
781     }
782     if(U_FAILURE(status))
783         log_err("FAIL: error in getSymbols() %s\n", myErrorName(status) );
784     resultlength=resultlengthout+1;
785 
786     udat_setSymbols(def, UDAT_MONTHS, 11, result, resultlength, &status);
787     if(U_FAILURE(status))
788         {
789             log_err("FAIL: Error in udat_setSymbols() : %s\n", myErrorName(status) );
790         }
791     else
792         log_verbose("PASS: SetSymbols successful\n");
793 
794     resultlength=0;
795     resultlengthout=udat_getSymbols(def, UDAT_MONTHS, 11, NULL, resultlength, &status);
796     if(status==U_BUFFER_OVERFLOW_ERROR){
797         status=U_ZERO_ERROR;
798         resultlength=resultlengthout+1;
799         value=(UChar*)malloc(sizeof(UChar) * resultlength);
800         udat_getSymbols(def, UDAT_MONTHS, 11, value, resultlength, &status);
801     }
802     if(U_FAILURE(status))
803         log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n");
804 
805     if(u_strcmp(result, value)!=0)
806         log_data_err("FAIL: Error in setting and getting symbols\n");
807     else
808         log_verbose("PASS: setSymbols successful\n");
809 
810 
811     /*run series of tests to test setSymbols regressively*/
812     log_verbose("\nTesting setSymbols regressively\n");
813     VerifysetSymbols(def, UDAT_ERAS, 0, "BeforeChrist");
814     VerifysetSymbols(def, UDAT_ERA_NAMES, 1, "AnnoDomini");
815     VerifysetSymbols(def, UDAT_WEEKDAYS, 1, "Sundayweek");
816     VerifysetSymbols(def, UDAT_SHORT_WEEKDAYS, 7, "Satweek");
817     VerifysetSymbols(def, UDAT_NARROW_WEEKDAYS, 4, "M");
818     VerifysetSymbols(def, UDAT_STANDALONE_WEEKDAYS, 1, "Sonntagweek");
819     VerifysetSymbols(def, UDAT_STANDALONE_SHORT_WEEKDAYS, 7, "Sams");
820     VerifysetSymbols(def, UDAT_STANDALONE_NARROW_WEEKDAYS, 4, "V");
821     VerifysetSymbols(fr, UDAT_MONTHS, 11, "december");
822     VerifysetSymbols(fr, UDAT_SHORT_MONTHS, 0, "Jan");
823     VerifysetSymbols(fr, UDAT_NARROW_MONTHS, 1, "R");
824     VerifysetSymbols(fr, UDAT_STANDALONE_MONTHS, 11, "dezember");
825     VerifysetSymbols(fr, UDAT_STANDALONE_SHORT_MONTHS, 7, "Aug");
826     VerifysetSymbols(fr, UDAT_STANDALONE_NARROW_MONTHS, 2, "M");
827     VerifysetSymbols(fr, UDAT_QUARTERS, 0, "1. Quart");
828     VerifysetSymbols(fr, UDAT_SHORT_QUARTERS, 1, "QQ2");
829     VerifysetSymbols(fr, UDAT_NARROW_QUARTERS, 1, "!2");
830     VerifysetSymbols(fr, UDAT_STANDALONE_QUARTERS, 2, "3rd Quar.");
831     VerifysetSymbols(fr, UDAT_STANDALONE_SHORT_QUARTERS, 3, "4QQ");
832     VerifysetSymbols(fr, UDAT_STANDALONE_NARROW_QUARTERS, 3, "!4");
833     VerifysetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_ABBREVIATED, 1, "yi-chou");
834     VerifysetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 1, "Ox");
835 
836 
837     /*run series of tests to test get and setSymbols regressively*/
838     log_verbose("\nTesting get and set symbols regressively\n");
839     VerifygetsetSymbols(fr, def, UDAT_WEEKDAYS, 1);
840     VerifygetsetSymbols(fr, def, UDAT_WEEKDAYS, 7);
841     VerifygetsetSymbols(fr, def, UDAT_SHORT_WEEKDAYS, 1);
842     VerifygetsetSymbols(fr, def, UDAT_SHORT_WEEKDAYS, 7);
843     VerifygetsetSymbols(fr, def, UDAT_MONTHS, 0);
844     VerifygetsetSymbols(fr, def, UDAT_SHORT_MONTHS, 0);
845     VerifygetsetSymbols(fr, def, UDAT_ERAS,1);
846     VerifygetsetSymbols(fr, def, UDAT_LOCALIZED_CHARS, 0);
847     VerifygetsetSymbols(fr, def, UDAT_AM_PMS, 1);
848 
849 
850     /*closing*/
851 
852     udat_close(fr);
853     udat_close(def);
854     udat_close(zhChiCal);
855     udat_close(esMX);
856     if(result != NULL) {
857         free(result);
858         result = NULL;
859     }
860     free(value);
861 
862 }
863 
864 /**
865  * Test DateFormat(Calendar) API
866  */
TestDateFormatCalendar(void)867 static void TestDateFormatCalendar(void) {
868     UDateFormat *date=0, *time=0, *full=0;
869     UCalendar *cal=0;
870     UChar buf[256];
871     char cbuf[256];
872     int32_t pos;
873     UDate when;
874     UErrorCode ec = U_ZERO_ERROR;
875     UChar buf1[256];
876     int32_t len1;
877     const char *expected;
878     UChar uExpected[32];
879 
880     ctest_setTimeZone(NULL, &ec);
881 
882     /* Create a formatter for date fields. */
883     date = udat_open(UDAT_NONE, UDAT_SHORT, "en_US", NULL, 0, NULL, 0, &ec);
884     if (U_FAILURE(ec)) {
885         log_data_err("FAIL: udat_open(NONE, SHORT, en_US) failed with %s (Are you missing data?)\n",
886                 u_errorName(ec));
887         goto FAIL;
888     }
889 
890     /* Create a formatter for time fields. */
891     time = udat_open(UDAT_SHORT, UDAT_NONE, "en_US", NULL, 0, NULL, 0, &ec);
892     if (U_FAILURE(ec)) {
893         log_err("FAIL: udat_open(SHORT, NONE, en_US) failed with %s\n",
894                 u_errorName(ec));
895         goto FAIL;
896     }
897 
898     /* Create a full format for output */
899     full = udat_open(UDAT_FULL, UDAT_FULL, "en_US", NULL, 0, NULL, 0, &ec);
900     if (U_FAILURE(ec)) {
901         log_err("FAIL: udat_open(FULL, FULL, en_US) failed with %s\n",
902                 u_errorName(ec));
903         goto FAIL;
904     }
905 
906     /* Create a calendar */
907     cal = ucal_open(NULL, 0, "en_US", UCAL_GREGORIAN, &ec);
908     if (U_FAILURE(ec)) {
909         log_err("FAIL: ucal_open(en_US) failed with %s\n",
910                 u_errorName(ec));
911         goto FAIL;
912     }
913 
914     /* Parse the date */
915     ucal_clear(cal);
916     u_uastrcpy(buf, "4/5/2001");
917     pos = 0;
918     udat_parseCalendar(date, cal, buf, -1, &pos, &ec);
919     if (U_FAILURE(ec)) {
920         log_err("FAIL: udat_parseCalendar(4/5/2001) failed at %d with %s\n",
921                 pos, u_errorName(ec));
922         goto FAIL;
923     }
924 
925     /* Check if formatCalendar matches the original date */
926     len1 = udat_formatCalendar(date, cal, buf1, UPRV_LENGTHOF(buf1), NULL, &ec);
927     if (U_FAILURE(ec)) {
928         log_err("FAIL: udat_formatCalendar(4/5/2001) failed with %s\n",
929                 u_errorName(ec));
930         goto FAIL;
931     }
932     expected = "4/5/01";
933     u_uastrcpy(uExpected, expected);
934     if (u_strlen(uExpected) != len1 || u_strncmp(uExpected, buf1, len1) != 0) {
935         log_err("FAIL: udat_formatCalendar(4/5/2001), expected: %s", expected);
936     }
937 
938     /* Parse the time */
939     u_uastrcpy(buf, "5:45 PM");
940     pos = 0;
941     udat_parseCalendar(time, cal, buf, -1, &pos, &ec);
942     if (U_FAILURE(ec)) {
943         log_err("FAIL: udat_parseCalendar(17:45) failed at %d with %s\n",
944                 pos, u_errorName(ec));
945         goto FAIL;
946     }
947 
948     /* Check if formatCalendar matches the original time */
949     len1 = udat_formatCalendar(time, cal, buf1, UPRV_LENGTHOF(buf1), NULL, &ec);
950     if (U_FAILURE(ec)) {
951         log_err("FAIL: udat_formatCalendar(17:45) failed with %s\n",
952                 u_errorName(ec));
953         goto FAIL;
954     }
955     u_strcpy(uExpected, u"5:45\u202FPM");
956     u_austrcpy(cbuf, uExpected);
957     if (u_strlen(uExpected) != len1 || u_strncmp(uExpected, buf1, len1) != 0) {
958         log_err("FAIL: udat_formatCalendar(17:45), expected: %s", cbuf);
959     }
960 
961     /* Check result */
962     when = ucal_getMillis(cal, &ec);
963     if (U_FAILURE(ec)) {
964         log_err("FAIL: ucal_getMillis() failed with %s\n", u_errorName(ec));
965         goto FAIL;
966     }
967     udat_format(full, when, buf, sizeof(buf), NULL, &ec);
968     if (U_FAILURE(ec)) {
969         log_err("FAIL: udat_format() failed with %s\n", u_errorName(ec));
970         goto FAIL;
971     }
972     u_austrcpy(cbuf, buf);
973     /* Thursday, April 5, 2001 5:45:00 PM PDT 986517900000 */
974     if (when == 986517900000.0) {
975         log_verbose("Ok: Parsed result: %s\n", cbuf);
976     } else {
977         log_err("FAIL: Parsed result: %s, exp 4/5/2001 5:45 PM\n", cbuf);
978     }
979 
980  FAIL:
981     udat_close(date);
982     udat_close(time);
983     udat_close(full);
984     ucal_close(cal);
985 
986     ctest_resetTimeZone();
987 }
988 
989 
990 
991 /**
992  * Test parsing two digit year against "YY" vs. "YYYY" patterns
993  */
TestCalendarDateParse(void)994 static void TestCalendarDateParse(void) {
995 
996     int32_t result;
997     UErrorCode ec = U_ZERO_ERROR;
998     UDateFormat* simpleDateFormat = 0;
999     int32_t parsePos = 0;
1000     int32_t twoDigitCenturyStart = 75;
1001     int32_t currentTwoDigitYear = 0;
1002     int32_t startCentury = 0;
1003     UCalendar* tempCal = 0;
1004     UCalendar* calendar = 0;
1005 
1006     U_STRING_DECL(pattern, "yyyy", 4);
1007     U_STRING_DECL(pattern2, "yy", 2);
1008     U_STRING_DECL(text, "75", 2);
1009 
1010     U_STRING_INIT(pattern, "yyyy", 4);
1011     U_STRING_INIT(pattern2, "yy", 2);
1012     U_STRING_INIT(text, "75", 2);
1013 
1014     simpleDateFormat = udat_open(UDAT_FULL, UDAT_FULL, "en-GB", 0, 0, 0, 0, &ec);
1015     if (U_FAILURE(ec)) {
1016         log_data_err("udat_open(UDAT_FULL, UDAT_FULL, \"en-GB\", 0, 0, 0, 0, &ec) failed: %s - (Are you missing data?)\n", u_errorName(ec));
1017         return;
1018     }
1019     udat_applyPattern(simpleDateFormat, 0, pattern, u_strlen(pattern));
1020     udat_setLenient(simpleDateFormat, 0);
1021 
1022     currentTwoDigitYear = getCurrentYear() % 100;
1023     startCentury = getCurrentYear() - currentTwoDigitYear;
1024     if (twoDigitCenturyStart > currentTwoDigitYear) {
1025       startCentury -= 100;
1026     }
1027     tempCal = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &ec);
1028     ucal_setMillis(tempCal, 0, &ec);
1029     ucal_setDateTime(tempCal, startCentury + twoDigitCenturyStart, UCAL_JANUARY, 1, 0, 0, 0, &ec);
1030     udat_set2DigitYearStart(simpleDateFormat, ucal_getMillis(tempCal, &ec), &ec);
1031 
1032     calendar = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &ec);
1033     ucal_setMillis(calendar, 0, &ec);
1034     ucal_setDateTime(calendar, twoDigitCenturyStart, UCAL_JANUARY, 1, 0, 0, 0, &ec);
1035 
1036     udat_parseCalendar(simpleDateFormat, calendar, text, u_strlen(text), &parsePos, &ec);
1037 
1038     /* Check result */
1039     result = ucal_get(calendar, UCAL_YEAR, &ec);
1040     if (U_FAILURE(ec)) {
1041         log_err("FAIL: ucal_get(UCAL_YEAR) failed with %s\n", u_errorName(ec));
1042         goto FAIL;
1043     }
1044 
1045     if (result != 75) {
1046         log_err("FAIL: parsed incorrect year: %d\n", result);
1047         goto FAIL;
1048     }
1049 
1050     parsePos = 0;
1051     udat_applyPattern(simpleDateFormat, 0, pattern2, u_strlen(pattern2));
1052     udat_parseCalendar(simpleDateFormat, calendar, text, u_strlen(text), &parsePos, &ec);
1053 
1054     /* Check result */
1055     result = ucal_get(calendar, UCAL_YEAR, &ec);
1056     if (U_FAILURE(ec)) {
1057         log_err("FAIL: ucal_get(UCAL_YEAR) failed with %s\n", u_errorName(ec));
1058         goto FAIL;
1059     }
1060 
1061     if (result != 1975) {
1062         log_err("FAIL: parsed incorrect year: %d\n", result);
1063         goto FAIL;
1064     }
1065 
1066  FAIL:
1067     udat_close(simpleDateFormat);
1068     ucal_close(tempCal);
1069     ucal_close(calendar);
1070 }
1071 
1072 
1073 /*INTERNAL FUNCTIONS USED*/
getCurrentYear(void)1074 static int getCurrentYear(void) {
1075     static int currentYear = 0;
1076     if (currentYear == 0) {
1077         UErrorCode status = U_ZERO_ERROR;
1078         UCalendar *cal = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &status);
1079         if (!U_FAILURE(status)) {
1080             /* Get the current year from the default UCalendar */
1081             currentYear = ucal_get(cal, UCAL_YEAR, &status);
1082             ucal_close(cal);
1083         }
1084     }
1085 
1086     return currentYear;
1087 }
1088 
1089 /* N.B.:  use idx instead of index to avoid 'shadow' warnings in strict mode. */
VerifygetSymbols(UDateFormat * datfor,UDateFormatSymbolType type,int32_t idx,const char * expected)1090 static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t idx, const char* expected)
1091 {
1092     UChar *pattern=NULL;
1093     UErrorCode status = U_ZERO_ERROR;
1094     UChar *result=NULL;
1095     int32_t resultlength, resultlengthout;
1096     int32_t patternSize = (int32_t)strlen(expected) + 1;
1097 
1098     pattern=(UChar*)malloc(sizeof(UChar) * patternSize);
1099     u_unescape(expected, pattern, patternSize);
1100     resultlength=0;
1101     resultlengthout=udat_getSymbols(datfor, type, idx , NULL, resultlength, &status);
1102     if(status==U_BUFFER_OVERFLOW_ERROR)
1103     {
1104         status=U_ZERO_ERROR;
1105         resultlength=resultlengthout+1;
1106         result=(UChar*)malloc(sizeof(UChar) * resultlength);
1107         udat_getSymbols(datfor, type, idx, result, resultlength, &status);
1108 
1109     }
1110     if(U_FAILURE(status))
1111     {
1112         log_err("FAIL: Error in udat_getSymbols()... %s\n", myErrorName(status) );
1113         return;
1114     }
1115     if(u_strcmp(result, pattern)==0)
1116         log_verbose("PASS: getSymbols retrieved the right value\n");
1117     else{
1118         log_data_err("FAIL: getSymbols retrieved the wrong value\n Expected %s Got %s\n", expected,
1119             aescstrdup(result,-1) );
1120     }
1121     free(result);
1122     free(pattern);
1123 }
1124 
VerifysetSymbols(UDateFormat * datfor,UDateFormatSymbolType type,int32_t idx,const char * expected)1125 static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, int32_t idx, const char* expected)
1126 {
1127     UChar *result=NULL;
1128     UChar *value=NULL;
1129     int32_t resultlength, resultlengthout;
1130     UErrorCode status = U_ZERO_ERROR;
1131     int32_t valueLen, valueSize = (int32_t)strlen(expected) + 1;
1132 
1133     value=(UChar*)malloc(sizeof(UChar) * valueSize);
1134     valueLen = u_unescape(expected, value, valueSize);
1135     udat_setSymbols(datfor, type, idx, value, valueLen, &status);
1136     if(U_FAILURE(status))
1137         {
1138             log_err("FAIL: Error in udat_setSymbols()  %s\n", myErrorName(status) );
1139             return;
1140         }
1141 
1142     resultlength=0;
1143     resultlengthout=udat_getSymbols(datfor, type, idx, NULL, resultlength, &status);
1144     if(status==U_BUFFER_OVERFLOW_ERROR){
1145         status=U_ZERO_ERROR;
1146         resultlength=resultlengthout+1;
1147         result=(UChar*)malloc(sizeof(UChar) * resultlength);
1148         udat_getSymbols(datfor, type, idx, result, resultlength, &status);
1149     }
1150     if(U_FAILURE(status)){
1151         log_err("FAIL: error in retrieving the value using getSymbols after setting it previously\n %s\n",
1152             myErrorName(status) );
1153         return;
1154     }
1155 
1156     if(u_strcmp(result, value)!=0){
1157         log_err("FAIL:Error in setting and then getting symbols\n Expected %s Got %s\n", expected,
1158             aescstrdup(result,-1) );
1159     }
1160     else
1161         log_verbose("PASS: setSymbols successful\n");
1162 
1163     free(value);
1164     free(result);
1165 }
1166 
1167 
VerifygetsetSymbols(UDateFormat * from,UDateFormat * to,UDateFormatSymbolType type,int32_t idx)1168 static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatSymbolType type, int32_t idx)
1169 {
1170     UChar *result=NULL;
1171     UChar *value=NULL;
1172     int32_t resultlength, resultlengthout;
1173     UErrorCode status = U_ZERO_ERROR;
1174 
1175     resultlength=0;
1176     resultlengthout=udat_getSymbols(from, type, idx , NULL, resultlength, &status);
1177     if(status==U_BUFFER_OVERFLOW_ERROR){
1178         status=U_ZERO_ERROR;
1179         resultlength=resultlengthout+1;
1180         result=(UChar*)malloc(sizeof(UChar) * resultlength);
1181         udat_getSymbols(from, type, idx, result, resultlength, &status);
1182     }
1183     if(U_FAILURE(status)){
1184         log_err("FAIL: error in getSymbols() %s\n", myErrorName(status) );
1185         return;
1186     }
1187 
1188     resultlength=resultlengthout+1;
1189     udat_setSymbols(to, type, idx, result, resultlength, &status);
1190     if(U_FAILURE(status))
1191         {
1192             log_err("FAIL: Error in udat_setSymbols() : %s\n", myErrorName(status) );
1193             return;
1194         }
1195 
1196     resultlength=0;
1197     resultlengthout=udat_getSymbols(to, type, idx, NULL, resultlength, &status);
1198     if(status==U_BUFFER_OVERFLOW_ERROR){
1199         status=U_ZERO_ERROR;
1200         resultlength=resultlengthout+1;
1201         value=(UChar*)malloc(sizeof(UChar) * resultlength);
1202         udat_getSymbols(to, type, idx, value, resultlength, &status);
1203     }
1204     if(U_FAILURE(status)){
1205         log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n %s\n",
1206             myErrorName(status) );
1207         return;
1208     }
1209 
1210     if(u_strcmp(result, value)!=0){
1211         log_data_err("FAIL:Error in setting and then getting symbols\n Expected %s Got %s\n", austrdup(result),
1212             austrdup(value) );
1213     }
1214     else
1215         log_verbose("PASS: setSymbols successful\n");
1216 
1217     free(value);
1218     free(result);
1219 }
1220 
1221 
myNumformat(const UNumberFormat * numfor,double d)1222 static UChar* myNumformat(const UNumberFormat* numfor, double d)
1223 {
1224     UChar *result2=NULL;
1225     int32_t resultlength, resultlengthneeded;
1226     UErrorCode status = U_ZERO_ERROR;
1227 
1228     resultlength=0;
1229     resultlengthneeded=unum_formatDouble(numfor, d, NULL, resultlength, NULL, &status);
1230     if(status==U_BUFFER_OVERFLOW_ERROR)
1231     {
1232         status=U_ZERO_ERROR;
1233         resultlength=resultlengthneeded+1;
1234         /*result2=(UChar*)malloc(sizeof(UChar) * resultlength);*/ /* this leaks */
1235         result2=(UChar*)ctst_malloc(sizeof(UChar) * resultlength); /*this won't*/
1236         unum_formatDouble(numfor, d, result2, resultlength, NULL, &status);
1237     }
1238     if(U_FAILURE(status))
1239     {
1240         log_err("FAIL: Error in formatting using unum_format(.....) %s\n", myErrorName(status) );
1241         return 0;
1242     }
1243 
1244     return result2;
1245 }
1246 
1247 /**
1248  * The search depth for TestExtremeDates.  The total number of
1249  * dates that will be tested is (2^EXTREME_DATES_DEPTH) - 1.
1250  */
1251 #define EXTREME_DATES_DEPTH 8
1252 
1253 /**
1254  * Support for TestExtremeDates (below).
1255  *
1256  * Test a single date to see whether udat_format handles it properly.
1257  */
_aux1ExtremeDates(UDateFormat * fmt,UDate date,UChar * buf,int32_t buflen,char * cbuf,UErrorCode * ec)1258 static UBool _aux1ExtremeDates(UDateFormat* fmt, UDate date,
1259                                UChar* buf, int32_t buflen, char* cbuf,
1260                                UErrorCode* ec) {
1261     int32_t len = udat_format(fmt, date, buf, buflen, 0, ec);
1262     if (!assertSuccess("udat_format", ec)) return false;
1263     u_austrncpy(cbuf, buf, buflen);
1264     if (len < 4) {
1265         log_err("FAIL: udat_format(%g) => \"%s\"\n", date, cbuf);
1266     } else {
1267         log_verbose("udat_format(%g) => \"%s\"\n", date, cbuf);
1268     }
1269     return true;
1270 }
1271 
1272 /**
1273  * Support for TestExtremeDates (below).
1274  *
1275  * Recursively test between 'small' and 'large', up to the depth
1276  * limit specified by EXTREME_DATES_DEPTH.
1277  */
_aux2ExtremeDates(UDateFormat * fmt,UDate small,UDate large,UChar * buf,int32_t buflen,char * cbuf,int32_t count,UErrorCode * ec)1278 static UBool _aux2ExtremeDates(UDateFormat* fmt, UDate small, UDate large,
1279                                UChar* buf, int32_t buflen, char* cbuf,
1280                                int32_t count,
1281                                UErrorCode* ec) {
1282     /* Logarithmic midpoint; see below */
1283     UDate mid = (UDate) exp((log(small) + log(large)) / 2);
1284     if (count == EXTREME_DATES_DEPTH) {
1285         return true;
1286     }
1287     return
1288         _aux1ExtremeDates(fmt, mid, buf, buflen, cbuf, ec) &&
1289         _aux2ExtremeDates(fmt, small, mid, buf, buflen, cbuf, count+1, ec) &&
1290         _aux2ExtremeDates(fmt, mid, large, buf, buflen, cbuf, count+1, ec);
1291 }
1292 
1293 /**
1294  * http://www.jtcsv.com/cgibin/icu-bugs?findid=3659
1295  *
1296  * For certain large dates, udat_format crashes on MacOS.  This test
1297  * attempts to reproduce this problem by doing a recursive logarithmic*
1298  * binary search of a predefined interval (from 'small' to 'large').
1299  *
1300  * The limit of the search is given by EXTREME_DATES_DEPTH, above.
1301  *
1302  * *The search has to be logarithmic, not linear.  A linear search of the
1303  *  range 0..10^30, for example, will find 0.5*10^30, then 0.25*10^30 and
1304  *  0.75*10^30, etc.  A logarithmic search will find 10^15, then 10^7.5
1305  *  and 10^22.5, etc.
1306  */
TestExtremeDates(void)1307 static void TestExtremeDates(void) {
1308     UDateFormat *fmt;
1309     UErrorCode ec;
1310     UChar buf[256];
1311     char cbuf[256];
1312     const double small = 1000; /* 1 sec */
1313     const double large = 1e+30; /* well beyond usable UDate range */
1314 
1315     /* There is no need to test larger values from 1e+30 to 1e+300;
1316        the failures occur around 1e+27, and never above 1e+30. */
1317 
1318     ec = U_ZERO_ERROR;
1319     fmt = udat_open(UDAT_LONG, UDAT_LONG, "en_US",
1320                     0, 0, 0, 0, &ec);
1321     if (U_FAILURE(ec)) {
1322         log_data_err("FAIL: udat_open (%s) (Are you missing data?)\n", u_errorName(ec));
1323         return;
1324     }
1325 
1326     _aux2ExtremeDates(fmt, small, large, buf, UPRV_LENGTHOF(buf), cbuf, 0, &ec);
1327 
1328     udat_close(fmt);
1329 }
1330 
TestAllLocales(void)1331 static void TestAllLocales(void) {
1332     int32_t idx, dateIdx, timeIdx, localeCount;
1333     static const UDateFormatStyle style[] = {
1334         UDAT_FULL, UDAT_LONG, UDAT_MEDIUM, UDAT_SHORT
1335     };
1336     localeCount = uloc_countAvailable();
1337     for (idx = 0; idx < localeCount; idx++) {
1338         for (dateIdx = 0; dateIdx < UPRV_LENGTHOF(style); dateIdx++) {
1339             for (timeIdx = 0; timeIdx < UPRV_LENGTHOF(style); timeIdx++) {
1340                 UErrorCode status = U_ZERO_ERROR;
1341                 udat_close(udat_open(style[dateIdx], style[timeIdx],
1342                     uloc_getAvailable(idx), NULL, 0, NULL, 0, &status));
1343                 if (U_FAILURE(status)) {
1344                     log_err("FAIL: udat_open(%s) failed with (%s) dateIdx=%d, timeIdx=%d\n",
1345                         uloc_getAvailable(idx), u_errorName(status), dateIdx, timeIdx);
1346                 }
1347             }
1348         }
1349     }
1350 }
1351 
TestRelativeCrash(void)1352 static void TestRelativeCrash(void) {
1353        static const UChar tzName[] = { 0x0055, 0x0053, 0x002F, 0x0050, 0x0061, 0x0063, 0x0069, 0x0066, 0x0069, 0x0063, 0 };
1354        static const UDate aDate = -631152000000.0;
1355 
1356     UErrorCode status = U_ZERO_ERROR;
1357     UErrorCode expectStatus = U_ILLEGAL_ARGUMENT_ERROR;
1358     UDateFormat icudf;
1359 
1360     icudf = udat_open(UDAT_NONE, UDAT_SHORT_RELATIVE, "en", tzName, -1, NULL, 0, &status);
1361     if ( U_SUCCESS(status) ) {
1362         const char *what = "???";
1363         {
1364             UErrorCode subStatus = U_ZERO_ERROR;
1365             what = "udat_set2DigitYearStart";
1366             log_verbose("Trying %s on a relative date..\n", what);
1367             udat_set2DigitYearStart(icudf, aDate, &subStatus);
1368             if(subStatus == expectStatus) {
1369                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1370             } else {
1371                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1372             }
1373         }
1374         {
1375             /* clone works polymorphically. try it anyways */
1376             UErrorCode subStatus = U_ZERO_ERROR;
1377             UDateFormat *oth;
1378             what = "clone";
1379             log_verbose("Trying %s on a relative date..\n", what);
1380             oth = udat_clone(icudf, &subStatus);
1381             if(subStatus == U_ZERO_ERROR) {
1382                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1383                 udat_close(oth); /* ? */
1384             } else {
1385                 log_err("FAIL: didn't crash on %s, but got  %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1386             }
1387         }
1388         {
1389             UErrorCode subStatus = U_ZERO_ERROR;
1390             what = "udat_get2DigitYearStart";
1391             log_verbose("Trying %s on a relative date..\n", what);
1392             udat_get2DigitYearStart(icudf, &subStatus);
1393             if(subStatus == expectStatus) {
1394                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1395             } else {
1396                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1397             }
1398         }
1399         {
1400             /* Now udat_toPattern works for relative date formatters, unless localized is true */
1401             UErrorCode subStatus = U_ZERO_ERROR;
1402             what = "udat_toPattern";
1403             log_verbose("Trying %s on a relative date..\n", what);
1404             udat_toPattern(icudf, true,NULL,0, &subStatus);
1405             if(subStatus == expectStatus) {
1406                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1407             } else {
1408                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1409             }
1410         }
1411         {
1412             UErrorCode subStatus = U_ZERO_ERROR;
1413             what = "udat_applyPattern";
1414             log_verbose("Trying %s on a relative date..\n", what);
1415             udat_applyPattern(icudf, false,tzName,-1);
1416             subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* what it should be, if this took an errorcode. */
1417             if(subStatus == expectStatus) {
1418                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1419             } else {
1420                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1421             }
1422         }
1423         {
1424             UChar erabuf[32];
1425             UErrorCode subStatus = U_ZERO_ERROR;
1426             what = "udat_getSymbols";
1427             log_verbose("Trying %s on a relative date..\n", what);
1428             udat_getSymbols(icudf, UDAT_ERAS,0,erabuf,UPRV_LENGTHOF(erabuf), &subStatus);
1429             if(subStatus == U_ZERO_ERROR) {
1430                 log_verbose("Success: %s returned %s.\n", what, u_errorName(subStatus));
1431             } else {
1432                 log_err("FAIL: didn't crash on %s, but got %s instead of U_ZERO_ERROR.\n", what, u_errorName(subStatus));
1433             }
1434         }
1435         {
1436             UErrorCode subStatus = U_ZERO_ERROR;
1437             UChar symbolValue = 0x0041;
1438             what = "udat_setSymbols";
1439             log_verbose("Trying %s on a relative date..\n", what);
1440             udat_setSymbols(icudf, UDAT_ERAS,0,&symbolValue,1, &subStatus);  /* bogus values */
1441             if(subStatus == expectStatus) {
1442                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1443             } else {
1444                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1445             }
1446         }
1447         {
1448             UErrorCode subStatus = U_ZERO_ERROR;
1449             what = "udat_countSymbols";
1450             log_verbose("Trying %s on a relative date..\n", what);
1451             udat_countSymbols(icudf, UDAT_ERAS);
1452             subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* should have an errorcode. */
1453             if(subStatus == expectStatus) {
1454                 log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
1455             } else {
1456                 log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
1457             }
1458         }
1459 
1460         udat_close(icudf);
1461     } else {
1462          log_data_err("FAIL: err calling udat_open() ->%s (Are you missing data?)\n", u_errorName(status));
1463     }
1464 }
1465 
1466 static const UChar skeleton_yMMMM[] = { 0x79,0x4D,0x4D,0x4D,0x4D,0 }; /* "yMMMM"; fr maps to "MMMM y", cs maps to "LLLL y" */
1467 static const UChar july2008_frDefault[] = { 0x6A,0x75,0x69,0x6C,0x6C,0x65,0x74,0x20,0x32,0x30,0x30,0x38,0 }; /* "juillet 2008" */
1468 static const UChar july2008_frTitle[] = { 0x4A,0x75,0x69,0x6C,0x6C,0x65,0x74,0x20,0x32,0x30,0x30,0x38,0 };  /* "Juillet 2008" sentence-begin, standalone */
1469 static const UChar july2008_csDefault[] = { 0x10D,0x65,0x72,0x76,0x65,0x6E,0x65,0x63,0x20,0x32,0x30,0x30,0x38,0 }; /* "c(hacek)ervenec 2008" */
1470 static const UChar july2008_csTitle[] = { 0x10C,0x65,0x72,0x76,0x65,0x6E,0x65,0x63,0x20,0x32,0x30,0x30,0x38,0 }; /* "C(hacek)ervenec 2008" sentence-begin, uiListOrMenu */
1471 
1472 typedef struct {
1473     const char * locale;
1474     const UChar * skeleton;
1475     UDisplayContext capitalizationContext;
1476     const UChar * expectedFormat;
1477 } TestContextItem;
1478 
1479 static const TestContextItem textContextItems[] = {
1480     { "fr", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_NONE,                   july2008_frDefault },
1481 #if !UCONFIG_NO_BREAK_ITERATION
1482     { "fr", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, july2008_frDefault },
1483     { "fr", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, july2008_frTitle },
1484     { "fr", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,    july2008_frDefault },
1485     { "fr", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,         july2008_frTitle },
1486 #endif
1487     { "cs", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_NONE,                   july2008_csDefault },
1488 #if !UCONFIG_NO_BREAK_ITERATION
1489     { "cs", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, july2008_csDefault },
1490     { "cs", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, july2008_csTitle },
1491     { "cs", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,    july2008_csTitle },
1492     { "cs", skeleton_yMMMM, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,         july2008_csDefault },
1493 #endif
1494     { NULL, NULL, (UDisplayContext)0, NULL }
1495 };
1496 
1497 static const UChar today_enDefault[]     = { 0x74,0x6F,0x64,0x61,0x79,0 }; /* "today" */
1498 static const UChar today_enTitle[]       = { 0x54,0x6F,0x64,0x61,0x79,0 };  /* "Today" sentence-begin, uiListOrMenu, standalone */
1499 static const UChar yesterday_enDefault[] = { 0x79,0x65,0x73,0x74,0x65,0x72,0x64,0x61,0x79,0 }; /* "yesterday" */
1500 static const UChar yesterday_enTitle[]   = { 0x59,0x65,0x73,0x74,0x65,0x72,0x64,0x61,0x79,0 };  /* "Yesterday" sentence-begin, uiListOrMenu, standalone */
1501 static const UChar today_nbDefault[]     = { 0x69,0x20,0x64,0x61,0x67,0 }; /* "i dag" */
1502 static const UChar today_nbTitle[]       = { 0x49,0x20,0x64,0x61,0x67,0 };  /* "I dag" sentence-begin, standalone */
1503 static const UChar yesterday_nbDefault[] = { 0x69,0x20,0x67,0xE5,0x72,0 };
1504 static const UChar yesterday_nbTitle[]   = { 0x49,0x20,0x67,0xE5,0x72,0 };
1505 
1506 typedef struct {
1507     const char * locale;
1508     UDisplayContext capitalizationContext;
1509     const UChar * expectedFormatToday;
1510     const UChar * expectedFormatYesterday;
1511 } TestRelativeContextItem;
1512 
1513 static const TestRelativeContextItem textContextRelativeItems[] = {
1514     { "en", UDISPCTX_CAPITALIZATION_NONE,                   today_enDefault, yesterday_enDefault },
1515 #if !UCONFIG_NO_BREAK_ITERATION
1516     { "en", UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, today_enDefault, yesterday_enDefault },
1517     { "en", UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, today_enTitle, yesterday_enTitle },
1518     { "en", UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,    today_enTitle, yesterday_enTitle },
1519     { "en", UDISPCTX_CAPITALIZATION_FOR_STANDALONE,         today_enTitle, yesterday_enTitle },
1520 #endif
1521     { "nb", UDISPCTX_CAPITALIZATION_NONE,                   today_nbDefault, yesterday_nbDefault },
1522 #if !UCONFIG_NO_BREAK_ITERATION
1523     { "nb", UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, today_nbDefault, yesterday_nbDefault },
1524     { "nb", UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, today_nbTitle, yesterday_nbTitle },
1525     { "nb", UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,    today_nbDefault, yesterday_nbDefault },
1526     { "nb", UDISPCTX_CAPITALIZATION_FOR_STANDALONE,         today_nbTitle, yesterday_nbTitle },
1527 #endif
1528     { NULL, (UDisplayContext)0, NULL, NULL }
1529 };
1530 
1531 static const UChar zoneGMT[] = { 0x47,0x4D,0x54,0 }; /* "GMT" */
1532 static const UDate july022008 = 1215000000000.0;
1533 enum { kUbufMax = 64, kBbufMax = 3*kUbufMax };
1534 
TestContext(void)1535 static void TestContext(void) {
1536     const TestContextItem* textContextItemPtr;
1537     const TestRelativeContextItem* textRelContextItemPtr;
1538     for (textContextItemPtr = textContextItems; textContextItemPtr->locale != NULL; ++textContextItemPtr) {
1539         UErrorCode status = U_ZERO_ERROR;
1540         UDateTimePatternGenerator* udtpg = udatpg_open(textContextItemPtr->locale, &status);
1541         if ( U_SUCCESS(status) ) {
1542             UChar ubuf[kUbufMax];
1543             int32_t len = udatpg_getBestPattern(udtpg, textContextItemPtr->skeleton, -1, ubuf, kUbufMax, &status);
1544             if ( U_SUCCESS(status) ) {
1545                 UDateFormat* udfmt = udat_open(UDAT_PATTERN, UDAT_PATTERN, textContextItemPtr->locale, zoneGMT, -1, ubuf, len, &status);
1546                 if ( U_SUCCESS(status) ) {
1547                     udat_setContext(udfmt, textContextItemPtr->capitalizationContext, &status);
1548                     if ( U_SUCCESS(status) ) {
1549                         UDisplayContext getContext;
1550                         len = udat_format(udfmt, july022008, ubuf, kUbufMax, NULL, &status);
1551                         if ( U_FAILURE(status) ) {
1552                             log_err("FAIL: udat_format for locale %s, capitalizationContext %d, status %s\n",
1553                                     textContextItemPtr->locale, (int)textContextItemPtr->capitalizationContext, u_errorName(status) );
1554                             status = U_ZERO_ERROR;
1555                         } else if (u_strncmp(ubuf, textContextItemPtr->expectedFormat, kUbufMax) != 0) {
1556                             char bbuf1[kBbufMax];
1557                             char bbuf2[kBbufMax];
1558                             log_err("FAIL: udat_format for locale %s, capitalizationContext %d, expected %s, got %s\n",
1559                                     textContextItemPtr->locale, (int)textContextItemPtr->capitalizationContext,
1560                                     u_austrncpy(bbuf1,textContextItemPtr->expectedFormat,kUbufMax), u_austrncpy(bbuf2,ubuf,kUbufMax) );
1561                         }
1562                         getContext = udat_getContext(udfmt, UDISPCTX_TYPE_CAPITALIZATION, &status);
1563                         if ( U_FAILURE(status) ) {
1564                             log_err("FAIL: udat_getContext for locale %s, capitalizationContext %d, status %s\n",
1565                                     textContextItemPtr->locale, (int)textContextItemPtr->capitalizationContext, u_errorName(status) );
1566                         } else if (getContext != textContextItemPtr->capitalizationContext) {
1567                             log_err("FAIL: udat_getContext for locale %s, capitalizationContext %d, got context %d\n",
1568                                     textContextItemPtr->locale, (int)textContextItemPtr->capitalizationContext, (int)getContext );
1569                         }
1570                     } else {
1571                         log_err("FAIL: udat_setContext for locale %s, capitalizationContext %d, status %s\n",
1572                                 textContextItemPtr->locale, (int)textContextItemPtr->capitalizationContext, u_errorName(status) );
1573                     }
1574                     udat_close(udfmt);
1575                 } else {
1576                     log_data_err("FAIL: udat_open for locale %s, status %s\n", textContextItemPtr->locale, u_errorName(status) );
1577                 }
1578             } else {
1579                 log_err("FAIL: udatpg_getBestPattern for locale %s, status %s\n", textContextItemPtr->locale, u_errorName(status) );
1580             }
1581             udatpg_close(udtpg);
1582         } else {
1583             log_data_err("FAIL: udatpg_open for locale %s, status %s\n", textContextItemPtr->locale, u_errorName(status) );
1584         }
1585     }
1586     for (textRelContextItemPtr = textContextRelativeItems; textRelContextItemPtr->locale != NULL; ++textRelContextItemPtr) {
1587         UErrorCode status = U_ZERO_ERROR;
1588         UCalendar* ucal = ucal_open(zoneGMT, -1, "root", UCAL_GREGORIAN, &status);
1589         if ( U_SUCCESS(status) ) {
1590             UDateFormat* udfmt = udat_open(UDAT_NONE, UDAT_LONG_RELATIVE, textRelContextItemPtr->locale, zoneGMT, -1, NULL, 0, &status);
1591             if ( U_SUCCESS(status) ) {
1592                 udat_setContext(udfmt, textRelContextItemPtr->capitalizationContext, &status);
1593                 if ( U_SUCCESS(status) ) {
1594                     UDate yesterday, today = ucal_getNow();
1595                     UChar ubuf[kUbufMax];
1596                     char bbuf1[kBbufMax];
1597                     char bbuf2[kBbufMax];
1598                     int32_t len = udat_format(udfmt, today, ubuf, kUbufMax, NULL, &status);
1599                     (void)len;
1600                     if ( U_FAILURE(status) ) {
1601                         log_err("FAIL: udat_format today for locale %s, capitalizationContext %d, status %s\n",
1602                                 textRelContextItemPtr->locale, (int)textRelContextItemPtr->capitalizationContext, u_errorName(status) );
1603                     } else if (u_strncmp(ubuf, textRelContextItemPtr->expectedFormatToday, kUbufMax) != 0) {
1604                         log_err("FAIL: udat_format today for locale %s, capitalizationContext %d, expected %s, got %s\n",
1605                                 textRelContextItemPtr->locale, (int)textRelContextItemPtr->capitalizationContext,
1606                                 u_austrncpy(bbuf1,textRelContextItemPtr->expectedFormatToday,kUbufMax), u_austrncpy(bbuf2,ubuf,kUbufMax) );
1607                     }
1608                     status = U_ZERO_ERROR;
1609                     ucal_setMillis(ucal, today, &status);
1610                     ucal_add(ucal, UCAL_DATE, -1, &status);
1611                     yesterday = ucal_getMillis(ucal, &status);
1612                     if ( U_SUCCESS(status) ) {
1613                         len = udat_format(udfmt, yesterday, ubuf, kUbufMax, NULL, &status);
1614                         if ( U_FAILURE(status) ) {
1615                             log_err("FAIL: udat_format yesterday for locale %s, capitalizationContext %d, status %s\n",
1616                                     textRelContextItemPtr->locale, (int)textRelContextItemPtr->capitalizationContext, u_errorName(status) );
1617                         } else if (u_strncmp(ubuf, textRelContextItemPtr->expectedFormatYesterday, kUbufMax) != 0) {
1618                             log_err("FAIL: udat_format yesterday for locale %s, capitalizationContext %d, expected %s, got %s\n",
1619                                     textRelContextItemPtr->locale, (int)textRelContextItemPtr->capitalizationContext,
1620                                     u_austrncpy(bbuf1,textRelContextItemPtr->expectedFormatYesterday,kUbufMax), u_austrncpy(bbuf2,ubuf,kUbufMax) );
1621                         }
1622                     }
1623                 } else {
1624                     log_err("FAIL: udat_setContext relative for locale %s, capitalizationContext %d, status %s\n",
1625                             textRelContextItemPtr->locale, (int)textRelContextItemPtr->capitalizationContext, u_errorName(status) );
1626                 }
1627                 udat_close(udfmt);
1628             } else {
1629                 log_data_err("FAIL: udat_open relative for locale %s, status %s\n", textRelContextItemPtr->locale, u_errorName(status) );
1630             }
1631             ucal_close(ucal);
1632         } else {
1633             log_data_err("FAIL: ucal_open for locale root, status %s\n", u_errorName(status) );
1634         }
1635     }
1636 }
1637 
1638 
1639 // overrideNumberFormat[i][0] is to tell which field to set,
1640 // overrideNumberFormat[i][1] is the expected result
1641 static const char * overrideNumberFormat[][2] = {
1642         {"", "\\u521D\\u4E03 \\u521D\\u4E8C"},
1643         {"d", "07 \\u521D\\u4E8C"},
1644         {"do", "07 \\u521D\\u4E8C"},
1645         {"Md", "\\u521D\\u4E03 \\u521D\\u4E8C"},
1646         {"MdMMd", "\\u521D\\u4E03 \\u521D\\u4E8C"},
1647         {"mixed", "\\u521D\\u4E03 \\u521D\\u4E8C"}
1648 };
1649 
TestOverrideNumberFormat(void)1650 static void TestOverrideNumberFormat(void) {
1651     UErrorCode status = U_ZERO_ERROR;
1652     UChar pattern[50];
1653     UChar expected[50];
1654     UChar fields[50];
1655     char bbuf1[kBbufMax];
1656     char bbuf2[kBbufMax];
1657     const char* localeString = "zh@numbers=hanidays";
1658     UDateFormat* fmt;
1659     const UNumberFormat* getter_result;
1660     int32_t i;
1661 
1662     u_uastrcpy(fields, "d");
1663     u_uastrcpy(pattern,"MM d");
1664 
1665     fmt=udat_open(UDAT_PATTERN, UDAT_PATTERN, "en_US", zoneGMT, -1, pattern, u_strlen(pattern), &status);
1666     if (!assertSuccess("udat_open()", &status)) {
1667         return;
1668     }
1669 
1670     // loop 5 times to check getter/setter
1671     for (i = 0; i < 5; i++){
1672         status = U_ZERO_ERROR;
1673         UNumberFormat* overrideFmt;
1674         overrideFmt = unum_open(UNUM_DEFAULT, NULL, 0, localeString, NULL, &status);
1675         assertSuccess("unum_open()", &status);
1676         udat_adoptNumberFormatForFields(fmt, fields, overrideFmt, &status);
1677         overrideFmt = NULL; // no longer valid
1678         assertSuccess("udat_setNumberFormatForField()", &status);
1679 
1680         getter_result = udat_getNumberFormatForField(fmt, 0x0064 /*'d'*/);
1681         if(getter_result == NULL) {
1682             log_err("FAIL: udat_getNumberFormatForField did not return a valid pointer\n");
1683         }
1684     }
1685     {
1686       status = U_ZERO_ERROR;
1687       UNumberFormat* overrideFmt;
1688       overrideFmt = unum_open(UNUM_DEFAULT, NULL, 0, localeString, NULL, &status);
1689       assertSuccess("unum_open()", &status);
1690       if (U_SUCCESS(status)) {
1691         udat_setNumberFormat(fmt, overrideFmt); // test the same override NF will not crash
1692       }
1693       unum_close(overrideFmt);
1694     }
1695     udat_close(fmt);
1696 
1697     for (i=0; i<UPRV_LENGTHOF(overrideNumberFormat); i++){
1698         status = U_ZERO_ERROR;
1699         UChar ubuf[kUbufMax];
1700         UDateFormat* fmt2;
1701         UNumberFormat* overrideFmt2;
1702 
1703         fmt2 =udat_open(UDAT_PATTERN, UDAT_PATTERN,"en_US", zoneGMT, -1, pattern, u_strlen(pattern), &status);
1704         assertSuccess("udat_open() with en_US", &status);
1705 
1706         overrideFmt2 = unum_open(UNUM_DEFAULT, NULL, 0, localeString, NULL, &status);
1707         assertSuccess("unum_open() in loop", &status);
1708 
1709         if (U_FAILURE(status)) {
1710             continue;
1711         }
1712 
1713         u_uastrcpy(fields, overrideNumberFormat[i][0]);
1714         u_unescape(overrideNumberFormat[i][1], expected, UPRV_LENGTHOF(expected));
1715 
1716         if ( strcmp(overrideNumberFormat[i][0], "") == 0 ) { // use the one w/o field
1717             udat_adoptNumberFormat(fmt2, overrideFmt2);
1718         } else if ( strcmp(overrideNumberFormat[i][0], "mixed") == 0 ) { // set 1 field at first but then full override, both(M & d) should be override
1719             const char* singleLocale = "en@numbers=hebr";
1720             UNumberFormat* singleOverrideFmt;
1721             u_uastrcpy(fields, "d");
1722 
1723             singleOverrideFmt = unum_open(UNUM_DEFAULT, NULL, 0, singleLocale, NULL, &status);
1724             assertSuccess("unum_open() in mixed", &status);
1725 
1726             udat_adoptNumberFormatForFields(fmt2, fields, singleOverrideFmt, &status);
1727             assertSuccess("udat_setNumberFormatForField() in mixed", &status);
1728 
1729             udat_adoptNumberFormat(fmt2, overrideFmt2);
1730         } else if ( strcmp(overrideNumberFormat[i][0], "do") == 0 ) { // o is an invalid field
1731             udat_adoptNumberFormatForFields(fmt2, fields, overrideFmt2, &status);
1732             if(status == U_INVALID_FORMAT_ERROR) {
1733                 udat_close(fmt2);
1734                 status = U_ZERO_ERROR;
1735                 continue;
1736             }
1737         } else {
1738             udat_adoptNumberFormatForFields(fmt2, fields, overrideFmt2, &status);
1739             assertSuccess("udat_setNumberFormatForField() in loop", &status);
1740         }
1741 
1742         udat_format(fmt2, july022008, ubuf, kUbufMax, NULL, &status);
1743         assertSuccess("udat_format() july022008", &status);
1744 
1745         if (u_strncmp(ubuf, expected, kUbufMax) != 0)
1746             log_err("fail: udat_format for locale, expected %s, got %s\n",
1747                     u_austrncpy(bbuf1,expected,kUbufMax), u_austrncpy(bbuf2,ubuf,kUbufMax) );
1748 
1749         udat_close(fmt2);
1750     }
1751 }
1752 
1753 /*
1754  * Ticket #11523
1755  * udat_parse and udat_parseCalendar should have the same error code when given the same invalid input.
1756  */
TestParseErrorReturnValue(void)1757 static void TestParseErrorReturnValue(void) {
1758     UErrorCode status = U_ZERO_ERROR;
1759     UErrorCode expectStatus = U_PARSE_ERROR;
1760     UDateFormat* df;
1761     UCalendar* cal;
1762 
1763     df = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, NULL, NULL, -1, NULL, -1, &status);
1764     if (!assertSuccessCheck("udat_open()", &status, true)) {
1765         return;
1766     }
1767 
1768     cal = ucal_open(NULL, 0, "en_US", UCAL_GREGORIAN, &status);
1769     if (!assertSuccess("ucal_open()", &status)) {
1770         return;
1771     }
1772 
1773     udat_parse(df, NULL, -1, NULL, &status);
1774     if (status != expectStatus) {
1775         log_err("%s should have been returned by udat_parse when given an invalid input, instead got - %s\n", u_errorName(expectStatus), u_errorName(status));
1776     }
1777 
1778     status = U_ZERO_ERROR;
1779     udat_parseCalendar(df, cal, NULL, -1, NULL, &status);
1780     if (status != expectStatus) {
1781         log_err("%s should have been returned by udat_parseCalendar when given an invalid input, instead got - %s\n", u_errorName(expectStatus), u_errorName(status));
1782     }
1783 
1784     ucal_close(cal);
1785     udat_close(df);
1786 }
1787 
1788 /*
1789  * Ticket #11553
1790  * Test new udat_formatForFields, udat_formatCalendarForFields (and UFieldPositionIterator)
1791  */
1792 static const char localeForFields[] = "en_US";
1793 /* zoneGMT[]defined above */
1794 static const UDate date2015Feb25 = 1424841000000.0; /* Wednesday, February 25, 2015 at 5:10:00 AM GMT */
1795 static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0078, 0x0078, 0x0027, 0 }; /* "'xxx'" */
1796 
1797 typedef struct {
1798     int32_t field;
1799     int32_t beginPos;
1800     int32_t endPos;
1801 } FieldsData;
1802 static const FieldsData expectedFields[] = {
1803     { UDAT_DAY_OF_WEEK_FIELD /* 9*/,      0,  9 },
1804     { UDAT_MONTH_FIELD /* 2*/,           11, 19 },
1805     { UDAT_DATE_FIELD /* 3*/,            20, 22 },
1806     { UDAT_YEAR_FIELD /* 1*/,            24, 28 },
1807     { UDAT_HOUR1_FIELD /*15*/,           32, 33 },
1808 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1809     { UDAT_TIME_SEPARATOR_FIELD /*35*/,  33, 34 },
1810 #endif
1811     { UDAT_MINUTE_FIELD /* 6*/,          34, 36 },
1812 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1813     { UDAT_TIME_SEPARATOR_FIELD /*35*/,  36, 37 },
1814 #endif
1815     { UDAT_SECOND_FIELD /* 7*/,          37, 39 },
1816     { UDAT_AM_PM_FIELD /*14*/,           40, 42 },
1817     { UDAT_TIMEZONE_FIELD /*17*/,        43, 46 },
1818     { -1,                                -1, -1 },
1819 };
1820 
1821 enum {kUBufFieldsLen = 128, kBBufFieldsLen = 256 };
1822 
TestFormatForFields(void)1823 static void TestFormatForFields(void) {
1824     UErrorCode status = U_ZERO_ERROR;
1825     UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
1826     if ( U_FAILURE(status) ) {
1827         log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
1828     } else {
1829         UDateFormat* udfmt = udat_open(UDAT_LONG, UDAT_FULL, localeForFields, zoneGMT, -1, NULL, 0, &status);
1830         UCalendar* ucal = ucal_open(zoneGMT, -1, localeForFields, UCAL_DEFAULT, &status);
1831         if ( U_FAILURE(status) ) {
1832             log_data_err("udat_open or ucal_open fails for locale %s, status %s (Are you missing data?)\n", localeForFields, u_errorName(status));
1833         } else {
1834             int32_t ulen, field, beginPos, endPos;
1835             UChar ubuf[kUBufFieldsLen];
1836             const FieldsData * fptr;
1837 
1838             status = U_ZERO_ERROR;
1839             ulen = udat_formatForFields(udfmt, date2015Feb25, ubuf, kUBufFieldsLen, fpositer, &status);
1840             if ( U_FAILURE(status) ) {
1841                 log_err("udat_formatForFields fails, status %s\n", u_errorName(status));
1842             } else {
1843                 for (fptr = expectedFields; ; fptr++) {
1844                     field = ufieldpositer_next(fpositer, &beginPos, &endPos);
1845                     if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
1846                         if (fptr->field >= 0) {
1847                             log_err("udat_formatForFields as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
1848                                     aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
1849                         } else {
1850                             log_err("udat_formatForFields as \"%s\"; expect field < 0, get field %d range %d-%d\n",
1851                                     aescstrdup(ubuf, ulen), field, beginPos, endPos);
1852                         }
1853                         break;
1854                     }
1855                     if (field < 0) {
1856                         break;
1857                     }
1858                 }
1859             }
1860 
1861             ucal_setMillis(ucal, date2015Feb25, &status);
1862             status = U_ZERO_ERROR;
1863             ulen = udat_formatCalendarForFields(udfmt, ucal, ubuf, kUBufFieldsLen, fpositer, &status);
1864             if ( U_FAILURE(status) ) {
1865                 log_err("udat_formatCalendarForFields fails, status %s\n", u_errorName(status));
1866             } else {
1867                 for (fptr = expectedFields; ; fptr++) {
1868                     field = ufieldpositer_next(fpositer, &beginPos, &endPos);
1869                     if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
1870                         if (fptr->field >= 0) {
1871                             log_err("udat_formatFudat_formatCalendarForFieldsorFields as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
1872                                     aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
1873                         } else {
1874                             log_err("udat_formatCalendarForFields as \"%s\"; expect field < 0, get field %d range %d-%d\n",
1875                                     aescstrdup(ubuf, ulen), field, beginPos, endPos);
1876                         }
1877                         break;
1878                     }
1879                     if (field < 0) {
1880                         break;
1881                     }
1882                 }
1883             }
1884 
1885             udat_applyPattern(udfmt, false, patNoFields, -1);
1886             status = U_ZERO_ERROR;
1887             ulen = udat_formatForFields(udfmt, date2015Feb25, ubuf, kUBufFieldsLen, fpositer, &status);
1888             if ( U_FAILURE(status) ) {
1889                 log_err("udat_formatForFields with no-field pattern fails, status %s\n", u_errorName(status));
1890             } else {
1891                 field = ufieldpositer_next(fpositer, &beginPos, &endPos);
1892                 if (field >= 0) {
1893                     log_err("udat_formatForFields with no-field pattern as \"%s\"; expect field < 0, get field %d range %d-%d\n",
1894                             aescstrdup(ubuf, ulen), field, beginPos, endPos);
1895                 }
1896             }
1897 
1898             ucal_close(ucal);
1899             udat_close(udfmt);
1900         }
1901         ufieldpositer_close(fpositer);
1902     }
1903 }
1904 
TestForceGannenNumbering(void)1905 static void TestForceGannenNumbering(void) {
1906     UErrorCode status;
1907     const char* locID = "ja_JP@calendar=japanese";
1908     UDate refDate = 600336000000.0; // 1989 Jan 9 Monday = Heisei 1
1909     const UChar* testSkeleton = u"yMMMd";
1910 
1911     // Test Gannen year forcing
1912     status = U_ZERO_ERROR;
1913     UDateTimePatternGenerator* dtpgen = udatpg_open(locID, &status);
1914     if (U_FAILURE(status)) {
1915         log_data_err("Fail in udatpg_open locale %s: %s", locID, u_errorName(status));
1916     } else {
1917         UChar pattern[kUbufMax];
1918         int32_t patlen = udatpg_getBestPattern(dtpgen, testSkeleton, -1, pattern, kUbufMax, &status);
1919         if (U_FAILURE(status)) {
1920             log_data_err("Fail in udatpg_getBestPattern locale %s: %s", locID, u_errorName(status));
1921         } else  {
1922             UDateFormat *testFmt = udat_open(UDAT_PATTERN, UDAT_PATTERN, locID, NULL, 0, pattern, patlen, &status);
1923             if (U_FAILURE(status)) {
1924                 log_data_err("Fail in udat_open locale %s: %s", locID, u_errorName(status));
1925             } else {
1926                 UChar testString[kUbufMax];
1927                 int32_t testStrLen = udat_format(testFmt, refDate, testString, kUbufMax, NULL, &status);
1928                 if (U_FAILURE(status)) {
1929                     log_err("Fail in udat_format locale %s: %s", locID, u_errorName(status));
1930                 } else if (testStrLen < 3 || testString[2] != 0x5143) {
1931                     char bbuf[kBbufMax];
1932                     u_austrncpy(bbuf, testString, testStrLen);
1933                     log_err("Formatting year 1 as Gannen, got%s but expected 3rd char to be 0x5143", bbuf);
1934                 }
1935                 udat_close(testFmt);
1936             }
1937         }
1938         udatpg_close(dtpgen);
1939     }
1940 }
1941 
1942 typedef struct {
1943     UChar               patternChar; // for future use
1944     UDateFormatField    dateField;
1945     UCalendarDateFields calField;
1946 } PatternCharToFieldsItem;
1947 
1948 static const PatternCharToFieldsItem patCharToFieldsItems[] = {
1949     { u'G', UDAT_ERA_FIELD,                 UCAL_ERA },
1950     { u'y', UDAT_YEAR_FIELD,                UCAL_YEAR },
1951     { u'Y', UDAT_YEAR_WOY_FIELD,            UCAL_YEAR_WOY },
1952     { u'Q', UDAT_QUARTER_FIELD,             UCAL_MONTH },
1953     { u'H', UDAT_HOUR_OF_DAY0_FIELD,        UCAL_HOUR_OF_DAY },
1954     { u'r', UDAT_RELATED_YEAR_FIELD,        UCAL_EXTENDED_YEAR },
1955     { u'B', UDAT_FLEXIBLE_DAY_PERIOD_FIELD, UCAL_FIELD_COUNT },
1956     { u'$', UDAT_FIELD_COUNT,               UCAL_FIELD_COUNT },
1957     { 0xFFFF, (UDateFormatField)-1,         UCAL_FIELD_COUNT }, // patternChar ignored here
1958     { (UChar)0, (UDateFormatField)0, (UCalendarDateFields)0 } // terminator
1959 };
1960 
TestMapDateToCalFields(void)1961 static void TestMapDateToCalFields(void){
1962     const PatternCharToFieldsItem* itemPtr;
1963     for ( itemPtr=patCharToFieldsItems; itemPtr->patternChar!=(UChar)0; itemPtr++) {
1964         UCalendarDateFields calField = udat_toCalendarDateField(itemPtr->dateField);
1965         if (calField != itemPtr->calField) {
1966             log_err("for pattern char 0x%04X, dateField %d, expect calField %d and got %d\n",
1967                     itemPtr->patternChar, itemPtr->dateField, itemPtr->calField, calField);
1968         }
1969     }
1970 }
1971 
TestNarrowQuarters(void)1972 static void TestNarrowQuarters(void) {
1973     // Test for rdar://79238094
1974     const UChar* testCases[] = {
1975         u"en_US", u"QQQQ y",  u"1st quarter 1970",
1976         u"en_US", u"QQQ y",   u"Q1 1970",
1977         u"en_US", u"QQQQQ y", u"1 1970",
1978         u"es_MX", u"QQQQ y",  u"1.º trimestre 1970",
1979         u"es_MX", u"QQQ y",   u"T1 1970",
1980         u"es_MX", u"QQQQQ y", u"1 1970",
1981         u"en_US", u"qqqq",    u"1st quarter",
1982         u"en_US", u"qqq",     u"Q1",
1983         u"en_US", u"qqqqq",   u"1",
1984         u"es_MX", u"qqqq",    u"1.º trimestre",
1985         u"es_MX", u"qqq",     u"T1",
1986         u"es_MX", u"qqqqq",   u"1",
1987     };
1988 
1989     UErrorCode err = U_ZERO_ERROR;
1990     UChar result[100];
1991     UDate parsedDate = 0;
1992     UDate expectedFormatParsedDate = 0;
1993     UDate expectedStandaloneParsedDate = 0;
1994 
1995     for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i += 3) {
1996         const UChar* localeID = testCases[i];
1997         const UChar* pattern = testCases[i + 1];
1998         const UChar* expectedResult = testCases[i + 2];
1999 
2000         err = U_ZERO_ERROR;
2001 
2002         UDateFormat* df = udat_open(UDAT_PATTERN, UDAT_PATTERN, austrdup(localeID), u"UTC", 0, pattern, -1, &err);
2003 
2004         udat_format(df, 0, result, 100, NULL, &err);
2005 
2006         if (assertSuccess("Formatting date failed", &err)) {
2007             assertUEquals("Wrong formatting result", expectedResult, result);
2008         }
2009 
2010         bool patternIsStandaloneQuarter = u_strchr(pattern, u'q') != NULL;
2011 
2012         parsedDate = udat_parse(df, expectedResult, -1, NULL, &err);
2013         if (!patternIsStandaloneQuarter && expectedFormatParsedDate == 0) {
2014             expectedFormatParsedDate = parsedDate;
2015         } else if (patternIsStandaloneQuarter && expectedStandaloneParsedDate == 0) {
2016             expectedStandaloneParsedDate = parsedDate;
2017         }
2018 
2019         if (assertSuccess("Parsing date failed", &err)) {
2020             if (patternIsStandaloneQuarter) {
2021                 assertDoubleEquals("Wrong parsing result", expectedStandaloneParsedDate, parsedDate);
2022             } else {
2023                 assertDoubleEquals("Wrong parsing result", expectedFormatParsedDate, parsedDate);
2024             }
2025         }
2026 
2027         udat_close(df);
2028     }
2029 }
2030 
TestExtraneousCharacters(void)2031 static void TestExtraneousCharacters(void) {
2032     // regression test for ICU-21802
2033     UErrorCode err = U_ZERO_ERROR;
2034     UCalendar* cal = ucal_open(u"UTC", -1, "en_US", UCAL_GREGORIAN, &err);
2035     UDateFormat* df = udat_open(UDAT_PATTERN, UDAT_PATTERN, "en_US", u"UTC", -1, u"yyyyMMdd", -1, &err);
2036 
2037     if (assertSuccess("Failed to create date formatter and calendar", &err)) {
2038         udat_setLenient(df, false);
2039 
2040         udat_parseCalendar(df, cal, u"2021", -1, NULL, &err);
2041         assertTrue("Success parsing '2021'", err == U_PARSE_ERROR);
2042 
2043         err = U_ZERO_ERROR;
2044         udat_parseCalendar(df, cal, u"2021-", -1, NULL, &err);
2045         assertTrue("Success parsing '2021-'", err == U_PARSE_ERROR);
2046     }
2047     udat_close(df);
2048     ucal_close(cal);
2049 }
2050 
TestParseTooStrict(void)2051 static void TestParseTooStrict(void) {
2052     UErrorCode status = U_ZERO_ERROR;
2053     const char* locale = "en_US";
2054     UDateFormat* df = udat_open(UDAT_PATTERN, UDAT_PATTERN, locale, u"UTC", -1, u"MM/dd/yyyy", -1, &status);
2055     if (U_FAILURE(status)) {
2056         log_data_err("udat_open locale %s pattern MM/dd/yyyy: %s\n", locale, u_errorName(status));
2057         return;
2058     }
2059     UCalendar* cal = ucal_open(u"UTC", -1, locale, UCAL_GREGORIAN, &status);
2060     if (U_FAILURE(status)) {
2061         log_data_err("ucal_open locale %s: %s\n", locale, u_errorName(status));
2062         udat_close(df);
2063         return;
2064     }
2065     ucal_clear(cal);
2066     int32_t ppos = 0;
2067     udat_setLenient(df, false);
2068     udat_parseCalendar(df, cal, u"1/1/2023", -1, &ppos, &status);
2069     if (U_FAILURE(status)) {
2070         log_err("udat_parseCalendar locale %s, 1/1/2023: %s\n", locale, u_errorName(status));
2071     } else if (ppos != 8) {
2072         log_err("udat_parseCalendar locale %s, 1/1/2023: ppos expect 8, get %d\n", locale, ppos);
2073     } else {
2074         UDate parsedDate = ucal_getMillis(cal, &status);
2075         if (U_FAILURE(status)) {
2076             log_err("ucal_getMillis: %s\n", u_errorName(status));
2077         } else if (parsedDate < 1672531200000.0 || parsedDate >= 1672617600000.0) { // check for day stating at UTC 2023-01-01 00:00
2078             log_err("udat_parseCalendar locale %s, 1/1/2023: parsed UDate %.0f out of range\n", locale, parsedDate);
2079         }
2080     }
2081 
2082     ucal_close(cal);
2083     udat_close(df);
2084 }
2085 
TestHourCycle(void)2086 static void TestHourCycle(void) {
2087     static const UDate date = -845601267742; // March 16, 1943 at 3:45 PM
2088     const UChar* testCases[] = {
2089         // test some locales for which we have data
2090         u"en_US", u"Tuesday, March 16, 1943 at 3:45:32 PM",
2091         u"en_CA", u"Tuesday, March 16, 1943 at 3:45:32 p.m.",
2092         u"en_GB", u"Tuesday 16 March 1943 at 15:45:32",
2093         u"en_AU", u"Tuesday 16 March 1943 at 3:45:32 pm",
2094         // test a couple locales for which we don't have specific locale files (we should still get the correct hour cycle)
2095         u"en_CO", u"Tuesday, March 16, 1943 at 3:45:32 PM",
2096         u"en_MX", u"Tuesday, March 16, 1943 at 3:45:32 PM",
2097         // test that the rg subtag does the right thing
2098         u"en_US@rg=GBzzzz", u"Tuesday, March 16, 1943 at 15:45:32",
2099         u"en_US@rg=CAzzzz", u"Tuesday, March 16, 1943 at 3:45:32 PM",
2100         u"en_CA@rg=USzzzz", u"Tuesday, March 16, 1943 at 3:45:32 p.m.",
2101         u"en_GB@rg=USzzzz", u"Tuesday 16 March 1943 at 3:45:32 pm",
2102         u"en_GB@rg=CAzzzz", u"Tuesday 16 March 1943 at 3:45:32 pm",
2103         u"en_GB@rg=AUzzzz", u"Tuesday 16 March 1943 at 3:45:32 pm",
2104         // test that the hc ("hours") subtag does the right thing
2105         u"en_US@hours=h23", u"Tuesday, March 16, 1943 at 15:45:32",
2106         u"en_GB@hours=h12", u"Tuesday 16 March 1943 at 3:45:32 pm",
2107         // test that the rg and hc subtags do the right thing when used together
2108         u"en_US@rg=GBzzzz;hours=h12", u"Tuesday, March 16, 1943 at 3:45:32 PM",
2109         u"en_GB@rg=USzzzz;hours=h23", u"Tuesday 16 March 1943 at 15:45:32",
2110     };
2111 
2112     for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i += 2) {
2113         char errorMessage[200];
2114         char* locale = austrdup(testCases[i]);
2115 
2116         UErrorCode err = U_ZERO_ERROR;
2117         sprintf(errorMessage, "Error creating formatter for %s", locale);
2118         if (assertSuccess(errorMessage, &err)) {
2119             UDateFormat* df = udat_open(UDAT_MEDIUM, UDAT_FULL, austrdup(testCases[i]), u"America/Los_Angeles", -1, NULL, 0, &err);
2120             sprintf(errorMessage, "Error formatting value for %s", locale);
2121             if (assertSuccess(errorMessage, &err)) {
2122                 UChar result[100];
2123                 udat_format(df, date, result, 100, NULL, &err);
2124 
2125                 sprintf(errorMessage, "Wrong result for %s", locale);
2126                 assertUEquals(errorMessage, testCases[i + 1], result);
2127 
2128                 udat_close(df);
2129             }
2130         }
2131     }
2132 }
2133 
TestLocaleNameCrash(void)2134 static void TestLocaleNameCrash(void) {
2135     UErrorCode status = U_ZERO_ERROR;
2136     UDateFormat icudf;
2137 
2138     icudf = udat_open(UDAT_MEDIUM, UDAT_NONE, "notalanguage", NULL, 0, NULL, 0, &status);
2139     if ( U_SUCCESS(status) ) {
2140         log_verbose("Success: did not crash on udat_open(locale=\"notalanguage\")\n");
2141     } else {
2142         log_err("FAIL: didn't crash on udat_open(locale=\"notalanguage\"), but got %s.\n", u_errorName(status));
2143     }
2144     udat_close(icudf);
2145 }
2146 
2147 #endif /* #if !UCONFIG_NO_FORMATTING */
2148