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