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
addRelativeDateFormatTest(TestNode ** root)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
TestRelDateFmt()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
TestCombineDateTime()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