1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * Copyright (c) 2016, International Business Machines Corporation 5 * and others. All Rights Reserved. 6 ********************************************************************/ 7 /* C API TEST FOR DATE INTERVAL FORMAT */ 8 9 #include "unicode/utypes.h" 10 11 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION 12 13 #include "unicode/ureldatefmt.h" 14 #include "unicode/unum.h" 15 #include "unicode/udisplaycontext.h" 16 #include "unicode/ustring.h" 17 #include "cintltst.h" 18 #include "cmemory.h" 19 20 static void TestRelDateFmt(void); 21 static void TestCombineDateTime(void); 22 23 void addRelativeDateFormatTest(TestNode** root); 24 25 #define TESTCASE(x) addTest(root, &x, "tsformat/crelativedateformattest/" #x) 26 27 void addRelativeDateFormatTest(TestNode** root) 28 { 29 TESTCASE(TestRelDateFmt); 30 TESTCASE(TestCombineDateTime); 31 } 32 33 static const double offsets[] = { -5.0, -2.2, -2.0, -1.0, -0.7, -0.0, 0.0, 0.7, 1.0, 2.0, 5.0 }; 34 enum { kNumOffsets = UPRV_LENGTHOF(offsets) }; 35 36 static const char* en_decDef_long_midSent_sec[kNumOffsets*2] = { 37 /* text numeric */ 38 "5 seconds ago", "5 seconds ago", /* -5 */ 39 "2.2 seconds ago", "2.2 seconds ago", /* -2.2 */ 40 "2 seconds ago", "2 seconds ago", /* -2 */ 41 "1 second ago", "1 second ago", /* -1 */ 42 "0.7 seconds ago", "0.7 seconds ago", /* -0.7 */ 43 "now", "0 seconds ago", /* -0 */ 44 "now", "in 0 seconds", /* 0 */ 45 "in 0.7 seconds", "in 0.7 seconds", /* 0.7 */ 46 "in 1 second", "in 1 second", /* 1 */ 47 "in 2 seconds", "in 2 seconds", /* 2 */ 48 "in 5 seconds", "in 5 seconds" /* 5 */ 49 }; 50 51 static const char* en_decDef_long_midSent_week[kNumOffsets*2] = { 52 /* text numeric */ 53 "5 weeks ago", "5 weeks ago", /* -5 */ 54 "2.2 weeks ago", "2.2 weeks ago", /* -2.2 */ 55 "2 weeks ago", "2 weeks ago", /* -2 */ 56 "last week", "1 week ago", /* -1 */ 57 "0.7 weeks ago", "0.7 weeks ago", /* -0.7 */ 58 "this week", "0 weeks ago", /* -0 */ 59 "this week", "in 0 weeks", /* 0 */ 60 "in 0.7 weeks", "in 0.7 weeks", /* 0.7 */ 61 "next week", "in 1 week", /* 1 */ 62 "in 2 weeks", "in 2 weeks", /* 2 */ 63 "in 5 weeks", "in 5 weeks" /* 5 */ 64 }; 65 66 static const char* en_dec0_long_midSent_week[kNumOffsets*2] = { 67 /* text numeric */ 68 "5 weeks ago", "5 weeks ago", /* -5 */ 69 "2 weeks ago", "2 weeks ago", /* -2.2 */ 70 "2 weeks ago", "2 weeks ago", /* -2 */ 71 "last week", "1 week ago", /* -1 */ 72 "0 weeks ago", "0 weeks ago", /* -0.7 */ 73 "this week", "0 weeks ago", /* -0 */ 74 "this week", "in 0 weeks", /* 0 */ 75 "in 0 weeks", "in 0 weeks", /* 0.7 */ 76 "next week", "in 1 week", /* 1 */ 77 "in 2 weeks", "in 2 weeks", /* 2 */ 78 "in 5 weeks", "in 5 weeks" /* 5 */ 79 }; 80 81 static const char* en_decDef_short_midSent_week[kNumOffsets*2] = { 82 /* text numeric */ 83 "5 wk. ago", "5 wk. ago", /* -5 */ 84 "2.2 wk. ago", "2.2 wk. ago", /* -2.2 */ 85 "2 wk. ago", "2 wk. ago", /* -2 */ 86 "last wk.", "1 wk. ago", /* -1 */ 87 "0.7 wk. ago", "0.7 wk. ago", /* -0.7 */ 88 "this wk.", "0 wk. ago", /* -0 */ 89 "this wk.", "in 0 wk.", /* 0 */ 90 "in 0.7 wk.", "in 0.7 wk.", /* 0.7 */ 91 "next wk.", "in 1 wk.", /* 1 */ 92 "in 2 wk.", "in 2 wk.", /* 2 */ 93 "in 5 wk.", "in 5 wk." /* 5 */ 94 }; 95 96 static const char* en_decDef_long_midSent_min[kNumOffsets*2] = { 97 /* text numeric */ 98 "5 minutes ago", "5 minutes ago", /* -5 */ 99 "2.2 minutes ago", "2.2 minutes ago", /* -2.2 */ 100 "2 minutes ago", "2 minutes ago", /* -2 */ 101 "1 minute ago", "1 minute ago", /* -1 */ 102 "0.7 minutes ago", "0.7 minutes ago", /* -0.7 */ 103 "0 minutes ago", "0 minutes ago", /* -0 */ 104 "in 0 minutes", "in 0 minutes", /* 0 */ 105 "in 0.7 minutes", "in 0.7 minutes", /* 0.7 */ 106 "in 1 minute", "in 1 minute", /* 1 */ 107 "in 2 minutes", "in 2 minutes", /* 2 */ 108 "in 5 minutes", "in 5 minutes" /* 5 */ 109 }; 110 111 static const char* en_dec0_long_midSent_tues[kNumOffsets*2] = { 112 /* text numeric */ 113 "5 Tuesdays ago", "5 Tuesdays ago", /* -5 */ 114 ""/*no data */, ""/*no data */, /* -2.2 */ 115 "2 Tuesdays ago", "2 Tuesdays ago", /* -2 */ 116 "last Tuesday", "1 Tuesday ago", /* -1 */ 117 ""/*no data */, ""/*no data */, /* -0.7 */ 118 "this Tuesday", "0 Tuesdays ago", /* -0 */ 119 "this Tuesday", "in 0 Tuesdays", /* 0 */ 120 ""/*no data */, ""/*no data */, /* 0.7 */ 121 "next Tuesday", "in 1 Tuesday", /* 1 */ 122 "in 2 Tuesdays", "in 2 Tuesdays", /* 2 */ 123 "in 5 Tuesdays", "in 5 Tuesdays", /* 5 */ 124 }; 125 126 static const char* fr_decDef_long_midSent_day[kNumOffsets*2] = { 127 /* text numeric */ 128 "il y a 5 jours", "il y a 5 jours", /* -5 */ 129 "il y a 2,2 jours", "il y a 2,2 jours", /* -2.2 */ 130 "avant-hier", "il y a 2 jours", /* -2 */ 131 "hier", "il y a 1 jour", /* -1 */ 132 "il y a 0,7 jour", "il y a 0,7 jour", /* -0.7 */ 133 "aujourd\\u2019hui", "il y a 0 jour", /* -0 */ 134 "aujourd\\u2019hui", "dans 0 jour", /* 0 */ 135 "dans 0,7 jour", "dans 0,7 jour", /* 0.7 */ 136 "demain", "dans 1 jour", /* 1 */ 137 "apr\\u00E8s-demain", "dans 2 jours", /* 2 */ 138 "dans 5 jours", "dans 5 jours" /* 5 */ 139 }; 140 141 142 typedef struct { 143 const char* locale; 144 int32_t decPlaces; /* fixed decimal places; -1 to use default num formatter */ 145 UDateRelativeDateTimeFormatterStyle width; 146 UDisplayContext capContext; 147 URelativeDateTimeUnit unit; 148 const char ** expectedResults; /* for the various offsets */ 149 } RelDateTimeFormatTestItem; 150 151 static const RelDateTimeFormatTestItem fmtTestItems[] = { 152 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_SECOND, en_decDef_long_midSent_sec }, 153 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_decDef_long_midSent_week }, 154 { "en", 0, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_dec0_long_midSent_week }, 155 { "en", -1, UDAT_STYLE_SHORT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_decDef_short_midSent_week }, 156 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_MINUTE, en_decDef_long_midSent_min }, 157 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_TUESDAY, en_dec0_long_midSent_tues }, 158 { "fr", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_DAY, fr_decDef_long_midSent_day }, 159 { NULL, 0, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, (URelativeDateTimeUnit)0, NULL } /* terminator */ 160 }; 161 162 enum { kUBufMax = 64, kBBufMax = 256 }; 163 164 static void TestRelDateFmt() 165 { 166 const RelDateTimeFormatTestItem *itemPtr; 167 log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n"); 168 for (itemPtr = fmtTestItems; itemPtr->locale != NULL; itemPtr++) { 169 URelativeDateTimeFormatter *reldatefmt = NULL; 170 UNumberFormat* nfToAdopt = NULL; 171 UErrorCode status = U_ZERO_ERROR; 172 int32_t iOffset; 173 174 if (itemPtr->decPlaces >= 0) { 175 nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status); 176 if ( U_FAILURE(status) ) { 177 log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status)); 178 continue; 179 } 180 unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces); 181 unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces); 182 unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN); 183 } 184 reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status); 185 if ( U_FAILURE(status) ) { 186 log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n", 187 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 188 myErrorName(status) ); 189 continue; 190 } 191 192 for (iOffset = 0; iOffset < kNumOffsets; iOffset++) { 193 UChar ubufget[kUBufMax]; 194 int32_t ulenget; 195 196 if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY && offsets[iOffset] != -1.0 && offsets[iOffset] != 0.0 && offsets[iOffset] != 1.0) { 197 continue; /* we do not currently have data for this */ 198 } 199 200 status = U_ZERO_ERROR; 201 ulenget = ureldatefmt_format(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); 202 if ( U_FAILURE(status) ) { 203 log_err("FAIL: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n", 204 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 205 offsets[iOffset], (int)itemPtr->unit, myErrorName(status) ); 206 } else { 207 UChar ubufexp[kUBufMax]; 208 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2], ubufexp, kUBufMax); 209 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { 210 char bbufget[kBBufMax]; 211 u_austrncpy(bbufget, ubufget, kUBufMax); 212 log_err("ERROR: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n expected %s\n get %s\n", 213 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 214 offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2], bbufget ); 215 } 216 } 217 218 if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY) { 219 continue; /* we do not currently have numeric-style data for this */ 220 } 221 222 status = U_ZERO_ERROR; 223 ulenget = ureldatefmt_formatNumeric(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); 224 if ( U_FAILURE(status) ) { 225 log_err("FAIL: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n", 226 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 227 offsets[iOffset], (int)itemPtr->unit, myErrorName(status) ); 228 } else { 229 UChar ubufexp[kUBufMax]; 230 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2 + 1], ubufexp, kUBufMax); 231 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { 232 char bbufget[kBBufMax]; 233 u_austrncpy(bbufget, ubufget, kUBufMax); 234 log_err("ERROR: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d;\n expected %s\n get %s\n", 235 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 236 offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2 + 1], bbufget ); 237 } 238 } 239 } 240 241 ureldatefmt_close(reldatefmt); 242 } 243 } 244 245 typedef struct { 246 const char* locale; 247 UDateRelativeDateTimeFormatterStyle width; 248 UDisplayContext capContext; 249 const char * relativeDateString; 250 const char * timeString; 251 const char * expectedResult; 252 } CombineDateTimeTestItem; 253 254 static const CombineDateTimeTestItem combTestItems[] = { 255 { "en", UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "yesterday", "3:45 PM", "yesterday, 3:45 PM" }, 256 { NULL, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, NULL, NULL, NULL } /* terminator */ 257 }; 258 259 static void TestCombineDateTime() 260 { 261 const CombineDateTimeTestItem *itemPtr; 262 log_verbose("\nTesting ureldatefmt_combineDateAndTime() with various parameters\n"); 263 for (itemPtr = combTestItems; itemPtr->locale != NULL; itemPtr++) { 264 URelativeDateTimeFormatter *reldatefmt = NULL; 265 UErrorCode status = U_ZERO_ERROR; 266 UChar ubufreldate[kUBufMax]; 267 UChar ubuftime[kUBufMax]; 268 UChar ubufget[kUBufMax]; 269 int32_t ulenreldate, ulentime, ulenget; 270 271 reldatefmt = ureldatefmt_open(itemPtr->locale, NULL, itemPtr->width, itemPtr->capContext, &status); 272 if ( U_FAILURE(status) ) { 273 log_data_err("FAIL: ureldatefmt_open() for locale %s, width %d, capContext %d: %s\n", 274 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 275 continue; 276 } 277 278 ulenreldate = u_unescape(itemPtr->relativeDateString, ubufreldate, kUBufMax); 279 ulentime = u_unescape(itemPtr->timeString, ubuftime, kUBufMax); 280 ulenget = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, ubufget, kUBufMax, &status); 281 if ( U_FAILURE(status) ) { 282 log_err("FAIL: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d: %s\n", 283 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 284 } else { 285 UChar ubufexp[kUBufMax]; 286 int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax); 287 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { 288 char bbufget[kBBufMax]; 289 u_austrncpy(bbufget, ubufget, kUBufMax); 290 log_err("ERROR: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d;\n expected %s\n get %s\n", 291 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, itemPtr->expectedResult, bbufget ); 292 } 293 } 294 // preflight test 295 status = U_ZERO_ERROR; 296 ulenget = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, NULL, 0, &status); 297 if ( status != U_BUFFER_OVERFLOW_ERROR) { 298 log_err("FAIL: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d: expected U_BUFFER_OVERFLOW_ERROR, got %s\n", 299 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 300 } else { 301 UChar ubufexp[kUBufMax]; 302 int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax); 303 if (ulenget != ulenexp) { 304 log_err("ERROR: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d;\n expected len %d, get len %d\n", 305 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, ulenexp, ulenget ); 306 } 307 } 308 309 ureldatefmt_close(reldatefmt); 310 } 311 } 312 313 #endif /* #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */ 314