1 // Copyright (C) 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.7, 1.0, 2.0, 5.0 }; 34 enum { kNumOffsets = UPRV_LENGTHOF(offsets) }; 35 36 static const char* en_decDef_long_midSent_week[kNumOffsets*2] = { 37 /* text numeric */ 38 "5 weeks ago", "5 weeks ago", /* -5 */ 39 "2.2 weeks ago", "2.2 weeks ago", /* -2.2 */ 40 "2 weeks ago", "2 weeks ago", /* -2 */ 41 "last week", "1 week ago", /* -1 */ 42 "0.7 weeks ago", "0.7 weeks ago", /* -0.7 */ 43 "this week", "in 0 weeks", /* 0 */ 44 "in 0.7 weeks", "in 0.7 weeks", /* 0.7 */ 45 "next week", "in 1 week", /* 1 */ 46 "in 2 weeks", "in 2 weeks", /* 2 */ 47 "in 5 weeks", "in 5 weeks" /* 5 */ 48 }; 49 50 static const char* en_dec0_long_midSent_week[kNumOffsets*2] = { 51 /* text numeric */ 52 "5 weeks ago", "5 weeks ago", /* -5 */ 53 "2 weeks ago", "2 weeks ago", /* -2.2 */ 54 "2 weeks ago", "2 weeks ago", /* -2 */ 55 "last week", "1 week ago", /* -1 */ 56 "0 weeks ago", "0 weeks ago", /* -0.7 */ 57 "this week", "in 0 weeks", /* 0 */ 58 "in 0 weeks", "in 0 weeks", /* 0.7 */ 59 "next week", "in 1 week", /* 1 */ 60 "in 2 weeks", "in 2 weeks", /* 2 */ 61 "in 5 weeks", "in 5 weeks" /* 5 */ 62 }; 63 64 static const char* en_decDef_short_midSent_week[kNumOffsets*2] = { 65 /* text numeric */ 66 "5 wk. ago", "5 wk. ago", /* -5 */ 67 "2.2 wk. ago", "2.2 wk. ago", /* -2.2 */ 68 "2 wk. ago", "2 wk. ago", /* -2 */ 69 "last wk.", "1 wk. ago", /* -1 */ 70 "0.7 wk. ago", "0.7 wk. ago", /* -0.7 */ 71 "this wk.", "in 0 wk.", /* 0 */ 72 "in 0.7 wk.", "in 0.7 wk.", /* 0.7 */ 73 "next wk.", "in 1 wk.", /* 1 */ 74 "in 2 wk.", "in 2 wk.", /* 2 */ 75 "in 5 wk.", "in 5 wk." /* 5 */ 76 }; 77 78 static const char* en_decDef_long_midSent_min[kNumOffsets*2] = { 79 /* text numeric */ 80 "5 minutes ago", "5 minutes ago", /* -5 */ 81 "2.2 minutes ago", "2.2 minutes ago", /* -2.2 */ 82 "2 minutes ago", "2 minutes ago", /* -2 */ 83 "1 minute ago", "1 minute ago", /* -1 */ 84 "0.7 minutes ago", "0.7 minutes ago", /* -0.7 */ 85 "in 0 minutes", "in 0 minutes", /* 0 */ 86 "in 0.7 minutes", "in 0.7 minutes", /* 0.7 */ 87 "in 1 minute", "in 1 minute", /* 1 */ 88 "in 2 minutes", "in 2 minutes", /* 2 */ 89 "in 5 minutes", "in 5 minutes" /* 5 */ 90 }; 91 92 static const char* en_dec0_long_midSent_tues[kNumOffsets*2] = { 93 /* text numeric */ 94 ""/*no data */, ""/*no data */, /* -5 */ 95 ""/*no data */, ""/*no data */, /* -2.2 */ 96 ""/*no data */, ""/*no data */, /* -2 */ 97 "last Tuesday", ""/*no data */, /* -1 */ 98 ""/*no data */, ""/*no data */, /* -0.7 */ 99 "this Tuesday", ""/*no data */, /* 0 */ 100 ""/*no data */, ""/*no data */, /* 0.7 */ 101 "next Tuesday", ""/*no data */, /* 1 */ 102 ""/*no data */, ""/*no data */, /* 2 */ 103 ""/*no data */, ""/*no data */, /* 5 */ 104 }; 105 106 static const char* fr_decDef_long_midSent_day[kNumOffsets*2] = { 107 /* text numeric */ 108 "il y a 5 jours", "il y a 5 jours", /* -5 */ 109 "il y a 2,2 jours", "il y a 2,2 jours", /* -2.2 */ 110 "avant-hier", "il y a 2 jours", /* -2 */ 111 "hier", "il y a 1 jour", /* -1 */ 112 "il y a 0,7 jour", "il y a 0,7 jour", /* -0.7 */ 113 "aujourd\\u2019hui", "dans 0 jour", /* 0 */ 114 "dans 0,7 jour", "dans 0,7 jour", /* 0.7 */ 115 "demain", "dans 1 jour", /* 1 */ 116 "apr\\u00E8s-demain", "dans 2 jours", /* 2 */ 117 "dans 5 jours", "dans 5 jours" /* 5 */ 118 }; 119 120 121 typedef struct { 122 const char* locale; 123 int32_t decPlaces; /* fixed decimal places; -1 to use default num formatter */ 124 UDateRelativeDateTimeFormatterStyle width; 125 UDisplayContext capContext; 126 URelativeDateTimeUnit unit; 127 const char ** expectedResults; /* for the various offsets */ 128 } RelDateTimeFormatTestItem; 129 130 static const RelDateTimeFormatTestItem fmtTestItems[] = { 131 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_decDef_long_midSent_week }, 132 { "en", 0, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_dec0_long_midSent_week }, 133 { "en", -1, UDAT_STYLE_SHORT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_decDef_short_midSent_week }, 134 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_MINUTE, en_decDef_long_midSent_min }, 135 { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_TUESDAY, en_dec0_long_midSent_tues }, 136 { "fr", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_DAY, fr_decDef_long_midSent_day }, 137 { NULL, 0, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, (URelativeDateTimeUnit)0, NULL } /* terminator */ 138 }; 139 140 enum { kUBufMax = 64, kBBufMax = 256 }; 141 142 static void TestRelDateFmt() 143 { 144 const RelDateTimeFormatTestItem *itemPtr; 145 log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n"); 146 for (itemPtr = fmtTestItems; itemPtr->locale != NULL; itemPtr++) { 147 URelativeDateTimeFormatter *reldatefmt = NULL; 148 UNumberFormat* nfToAdopt = NULL; 149 UErrorCode status = U_ZERO_ERROR; 150 int32_t iOffset; 151 152 if (itemPtr->decPlaces >= 0) { 153 nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status); 154 if ( U_FAILURE(status) ) { 155 log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status)); 156 continue; 157 } 158 unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces); 159 unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces); 160 unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN); 161 } 162 reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status); 163 if ( U_FAILURE(status) ) { 164 log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n", 165 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 166 myErrorName(status) ); 167 continue; 168 } 169 170 for (iOffset = 0; iOffset < kNumOffsets; iOffset++) { 171 UChar ubufget[kUBufMax]; 172 int32_t ulenget; 173 174 if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY && offsets[iOffset] != -1.0 && offsets[iOffset] != 0.0 && offsets[iOffset] != 1.0) { 175 continue; /* we do not currently have data for this */ 176 } 177 178 status = U_ZERO_ERROR; 179 ulenget = ureldatefmt_format(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); 180 if ( U_FAILURE(status) ) { 181 log_err("FAIL: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n", 182 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 183 offsets[iOffset], (int)itemPtr->unit, myErrorName(status) ); 184 } else { 185 UChar ubufexp[kUBufMax]; 186 int32_t ulenexp = u_unescape(itemPtr->expectedResults[iOffset*2], ubufexp, kUBufMax); 187 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { 188 char bbufget[kBBufMax]; 189 u_austrncpy(bbufget, ubufget, kUBufMax); 190 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", 191 itemPtr->locale, itemPtr->decPlaces, (int)itemPtr->width, (int)itemPtr->capContext, 192 offsets[iOffset], (int)itemPtr->unit, itemPtr->expectedResults[iOffset*2], bbufget ); 193 } 194 } 195 196 if (itemPtr->unit >= UDAT_REL_UNIT_SUNDAY) { 197 continue; /* we do not currently have numeric-style data for this */ 198 } 199 200 status = U_ZERO_ERROR; 201 ulenget = ureldatefmt_formatNumeric(reldatefmt, offsets[iOffset], itemPtr->unit, ubufget, kUBufMax, &status); 202 if ( U_FAILURE(status) ) { 203 log_err("FAIL: ureldatefmt_formatNumeric() 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 + 1], 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_formatNumeric() 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 + 1], bbufget ); 215 } 216 } 217 } 218 219 ureldatefmt_close(reldatefmt); 220 } 221 } 222 223 typedef struct { 224 const char* locale; 225 UDateRelativeDateTimeFormatterStyle width; 226 UDisplayContext capContext; 227 const char * relativeDateString; 228 const char * timeString; 229 const char * expectedResult; 230 } CombineDateTimeTestItem; 231 232 static const CombineDateTimeTestItem combTestItems[] = { 233 { "en", UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "yesterday", "3:45 PM", "yesterday, 3:45 PM" }, 234 { NULL, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, NULL, NULL, NULL } /* terminator */ 235 }; 236 237 static void TestCombineDateTime() 238 { 239 const CombineDateTimeTestItem *itemPtr; 240 log_verbose("\nTesting ureldatefmt_combineDateAndTime() with various parameters\n"); 241 for (itemPtr = combTestItems; itemPtr->locale != NULL; itemPtr++) { 242 URelativeDateTimeFormatter *reldatefmt = NULL; 243 UErrorCode status = U_ZERO_ERROR; 244 UChar ubufreldate[kUBufMax]; 245 UChar ubuftime[kUBufMax]; 246 UChar ubufget[kUBufMax]; 247 int32_t ulenreldate, ulentime, ulenget; 248 249 reldatefmt = ureldatefmt_open(itemPtr->locale, NULL, itemPtr->width, itemPtr->capContext, &status); 250 if ( U_FAILURE(status) ) { 251 log_data_err("FAIL: ureldatefmt_open() for locale %s, width %d, capContext %d: %s\n", 252 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 253 continue; 254 } 255 256 ulenreldate = u_unescape(itemPtr->relativeDateString, ubufreldate, kUBufMax); 257 ulentime = u_unescape(itemPtr->timeString, ubuftime, kUBufMax); 258 ulenget = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, ubufget, kUBufMax, &status); 259 if ( U_FAILURE(status) ) { 260 log_err("FAIL: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d: %s\n", 261 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 262 } else { 263 UChar ubufexp[kUBufMax]; 264 int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax); 265 if (ulenget != ulenexp || u_strncmp(ubufget, ubufexp, ulenexp) != 0) { 266 char bbufget[kBBufMax]; 267 u_austrncpy(bbufget, ubufget, kUBufMax); 268 log_err("ERROR: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d;\n expected %s\n get %s\n", 269 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, itemPtr->expectedResult, bbufget ); 270 } 271 } 272 // preflight test 273 status = U_ZERO_ERROR; 274 ulenget = ureldatefmt_combineDateAndTime(reldatefmt, ubufreldate, ulenreldate, ubuftime, ulentime, NULL, 0, &status); 275 if ( status != U_BUFFER_OVERFLOW_ERROR) { 276 log_err("FAIL: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d: expected U_BUFFER_OVERFLOW_ERROR, got %s\n", 277 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, myErrorName(status) ); 278 } else { 279 UChar ubufexp[kUBufMax]; 280 int32_t ulenexp = u_unescape(itemPtr->expectedResult, ubufexp, kUBufMax); 281 if (ulenget != ulenexp) { 282 log_err("ERROR: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d;\n expected len %d, get len %d\n", 283 itemPtr->locale, (int)itemPtr->width, (int)itemPtr->capContext, ulenexp, ulenget ); 284 } 285 } 286 287 ureldatefmt_close(reldatefmt); 288 } 289 } 290 291 #endif /* #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */ 292