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 */
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION
13 #include "unicode/ureldatefmt.h"
14 #include "unicode/unum.h"
15 #include "unicode/udisplaycontext.h"
16 #include "unicode/ustring.h"
20 static void TestRelDateFmt(void);
21 static void TestCombineDateTime(void);
23 void addRelativeDateFormatTest(TestNode
** root
);
25 #define TESTCASE(x) addTest(root, &x, "tsformat/crelativedateformattest/" #x)
27 void addRelativeDateFormatTest(TestNode
** root
)
29 TESTCASE(TestRelDateFmt
);
30 TESTCASE(TestCombineDateTime
);
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
) };
36 static const char* en_decDef_long_midSent_sec
[kNumOffsets
*2] = {
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 */
51 static const char* en_decDef_long_midSent_week
[kNumOffsets
*2] = {
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 */
66 static const char* en_dec0_long_midSent_week
[kNumOffsets
*2] = {
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 */
81 static const char* en_decDef_short_midSent_week
[kNumOffsets
*2] = {
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 */
96 static const char* en_decDef_long_midSent_min
[kNumOffsets
*2] = {
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 */
111 static const char* en_dec0_long_midSent_tues
[kNumOffsets
*2] = {
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 */
126 static const char* fr_decDef_long_midSent_day
[kNumOffsets
*2] = {
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 */
141 static const char* nb_decDef_long_midSent_day
[kNumOffsets
*2] = {
143 "for 5 dager siden", "for 5 dager siden", /* -5 */
144 "for 2,2 dager siden", "for 2,2 dager siden", /* -2.2 */
145 "i forg\\u00E5rs", "for 2 dager siden", /* -2 */
146 "i g\\u00E5r", "for 1 dag siden", /* -1 */
147 "for 0,7 dager siden", "for 0,7 dager siden", /* -0.7 */
148 "i dag", "for 0 dager siden", /* -0 */
149 "i dag", "om 0 dager", /* 0 */
150 "om 0,7 dager", "om 0,7 dager", /* 0.7 */
151 "i morgen", "om 1 dag", /* 1 */
152 "i overmorgen", "om 2 dager", /* 2 */
153 "om 5 dager", "om 5 dager" /* 5 */
159 int32_t decPlaces
; /* fixed decimal places; -1 to use default num formatter */
160 UDateRelativeDateTimeFormatterStyle width
;
161 UDisplayContext capContext
;
162 URelativeDateTimeUnit unit
;
163 const char ** expectedResults
; /* for the various offsets */
164 } RelDateTimeFormatTestItem
;
166 static const RelDateTimeFormatTestItem fmtTestItems
[] = {
167 { "en", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_SECOND
, en_decDef_long_midSent_sec
},
168 { "en", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_WEEK
, en_decDef_long_midSent_week
},
169 { "en", 0, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_WEEK
, en_dec0_long_midSent_week
},
170 { "en", -1, UDAT_STYLE_SHORT
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_WEEK
, en_decDef_short_midSent_week
},
171 { "en", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_MINUTE
, en_decDef_long_midSent_min
},
172 { "en", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_TUESDAY
, en_dec0_long_midSent_tues
},
173 { "fr", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_DAY
, fr_decDef_long_midSent_day
},
174 { "nb", -1, UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, UDAT_REL_UNIT_DAY
, nb_decDef_long_midSent_day
},
175 { NULL
, 0, (UDateRelativeDateTimeFormatterStyle
)0, (UDisplayContext
)0, (URelativeDateTimeUnit
)0, NULL
} /* terminator */
178 enum { kUBufMax
= 64, kBBufMax
= 256 };
180 static void TestRelDateFmt()
182 const RelDateTimeFormatTestItem
*itemPtr
;
183 log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n");
184 for (itemPtr
= fmtTestItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
185 URelativeDateTimeFormatter
*reldatefmt
= NULL
;
186 UNumberFormat
* nfToAdopt
= NULL
;
187 UErrorCode status
= U_ZERO_ERROR
;
190 if (itemPtr
->decPlaces
>= 0) {
191 nfToAdopt
= unum_open(UNUM_DECIMAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
192 if ( U_FAILURE(status
) ) {
193 log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr
->locale
, myErrorName(status
));
196 unum_setAttribute(nfToAdopt
, UNUM_MIN_FRACTION_DIGITS
, itemPtr
->decPlaces
);
197 unum_setAttribute(nfToAdopt
, UNUM_MAX_FRACTION_DIGITS
, itemPtr
->decPlaces
);
198 unum_setAttribute(nfToAdopt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_DOWN
);
200 reldatefmt
= ureldatefmt_open(itemPtr
->locale
, nfToAdopt
, itemPtr
->width
, itemPtr
->capContext
, &status
);
201 if ( U_FAILURE(status
) ) {
202 log_data_err("FAIL: ureldatefmt_open() for locale %s, decPlaces %d, width %d, capContext %d: %s\n",
203 itemPtr
->locale
, itemPtr
->decPlaces
, (int)itemPtr
->width
, (int)itemPtr
->capContext
,
204 myErrorName(status
) );
208 for (iOffset
= 0; iOffset
< kNumOffsets
; iOffset
++) {
209 UChar ubufget
[kUBufMax
];
212 if (itemPtr
->unit
>= UDAT_REL_UNIT_SUNDAY
&& offsets
[iOffset
] != -1.0 && offsets
[iOffset
] != 0.0 && offsets
[iOffset
] != 1.0) {
213 continue; /* we do not currently have data for this */
216 status
= U_ZERO_ERROR
;
217 ulenget
= ureldatefmt_format(reldatefmt
, offsets
[iOffset
], itemPtr
->unit
, ubufget
, kUBufMax
, &status
);
218 if ( U_FAILURE(status
) ) {
219 log_err("FAIL: ureldatefmt_format() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
220 itemPtr
->locale
, itemPtr
->decPlaces
, (int)itemPtr
->width
, (int)itemPtr
->capContext
,
221 offsets
[iOffset
], (int)itemPtr
->unit
, myErrorName(status
) );
223 UChar ubufexp
[kUBufMax
];
224 int32_t ulenexp
= u_unescape(itemPtr
->expectedResults
[iOffset
*2], ubufexp
, kUBufMax
);
225 if (ulenget
!= ulenexp
|| u_strncmp(ubufget
, ubufexp
, ulenexp
) != 0) {
226 char bbufget
[kBBufMax
];
227 u_austrncpy(bbufget
, ubufget
, kUBufMax
);
228 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",
229 itemPtr
->locale
, itemPtr
->decPlaces
, (int)itemPtr
->width
, (int)itemPtr
->capContext
,
230 offsets
[iOffset
], (int)itemPtr
->unit
, itemPtr
->expectedResults
[iOffset
*2], bbufget
);
234 if (itemPtr
->unit
>= UDAT_REL_UNIT_SUNDAY
) {
235 continue; /* we do not currently have numeric-style data for this */
238 status
= U_ZERO_ERROR
;
239 ulenget
= ureldatefmt_formatNumeric(reldatefmt
, offsets
[iOffset
], itemPtr
->unit
, ubufget
, kUBufMax
, &status
);
240 if ( U_FAILURE(status
) ) {
241 log_err("FAIL: ureldatefmt_formatNumeric() for locale %s, decPlaces %d, width %d, capContext %d, offset %.2f, unit %d: %s\n",
242 itemPtr
->locale
, itemPtr
->decPlaces
, (int)itemPtr
->width
, (int)itemPtr
->capContext
,
243 offsets
[iOffset
], (int)itemPtr
->unit
, myErrorName(status
) );
245 UChar ubufexp
[kUBufMax
];
246 int32_t ulenexp
= u_unescape(itemPtr
->expectedResults
[iOffset
*2 + 1], ubufexp
, kUBufMax
);
247 if (ulenget
!= ulenexp
|| u_strncmp(ubufget
, ubufexp
, ulenexp
) != 0) {
248 char bbufget
[kBBufMax
];
249 u_austrncpy(bbufget
, ubufget
, kUBufMax
);
250 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",
251 itemPtr
->locale
, itemPtr
->decPlaces
, (int)itemPtr
->width
, (int)itemPtr
->capContext
,
252 offsets
[iOffset
], (int)itemPtr
->unit
, itemPtr
->expectedResults
[iOffset
*2 + 1], bbufget
);
257 ureldatefmt_close(reldatefmt
);
263 UDateRelativeDateTimeFormatterStyle width
;
264 UDisplayContext capContext
;
265 const char * relativeDateString
;
266 const char * timeString
;
267 const char * expectedResult
;
268 } CombineDateTimeTestItem
;
270 static const CombineDateTimeTestItem combTestItems
[] = {
271 { "en", UDAT_STYLE_LONG
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, "yesterday", "3:45 PM", "yesterday, 3:45 PM" },
272 { NULL
, (UDateRelativeDateTimeFormatterStyle
)0, (UDisplayContext
)0, NULL
, NULL
, NULL
} /* terminator */
275 static void TestCombineDateTime()
277 const CombineDateTimeTestItem
*itemPtr
;
278 log_verbose("\nTesting ureldatefmt_combineDateAndTime() with various parameters\n");
279 for (itemPtr
= combTestItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
280 URelativeDateTimeFormatter
*reldatefmt
= NULL
;
281 UErrorCode status
= U_ZERO_ERROR
;
282 UChar ubufreldate
[kUBufMax
];
283 UChar ubuftime
[kUBufMax
];
284 UChar ubufget
[kUBufMax
];
285 int32_t ulenreldate
, ulentime
, ulenget
;
287 reldatefmt
= ureldatefmt_open(itemPtr
->locale
, NULL
, itemPtr
->width
, itemPtr
->capContext
, &status
);
288 if ( U_FAILURE(status
) ) {
289 log_data_err("FAIL: ureldatefmt_open() for locale %s, width %d, capContext %d: %s\n",
290 itemPtr
->locale
, (int)itemPtr
->width
, (int)itemPtr
->capContext
, myErrorName(status
) );
294 ulenreldate
= u_unescape(itemPtr
->relativeDateString
, ubufreldate
, kUBufMax
);
295 ulentime
= u_unescape(itemPtr
->timeString
, ubuftime
, kUBufMax
);
296 ulenget
= ureldatefmt_combineDateAndTime(reldatefmt
, ubufreldate
, ulenreldate
, ubuftime
, ulentime
, ubufget
, kUBufMax
, &status
);
297 if ( U_FAILURE(status
) ) {
298 log_err("FAIL: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d: %s\n",
299 itemPtr
->locale
, (int)itemPtr
->width
, (int)itemPtr
->capContext
, myErrorName(status
) );
301 UChar ubufexp
[kUBufMax
];
302 int32_t ulenexp
= u_unescape(itemPtr
->expectedResult
, ubufexp
, kUBufMax
);
303 if (ulenget
!= ulenexp
|| u_strncmp(ubufget
, ubufexp
, ulenexp
) != 0) {
304 char bbufget
[kBBufMax
];
305 u_austrncpy(bbufget
, ubufget
, kUBufMax
);
306 log_err("ERROR: ureldatefmt_combineDateAndTime() for locale %s, width %d, capContext %d;\n expected %s\n get %s\n",
307 itemPtr
->locale
, (int)itemPtr
->width
, (int)itemPtr
->capContext
, itemPtr
->expectedResult
, bbufget
);
311 status
= U_ZERO_ERROR
;
312 ulenget
= ureldatefmt_combineDateAndTime(reldatefmt
, ubufreldate
, ulenreldate
, ubuftime
, ulentime
, NULL
, 0, &status
);
313 if ( status
!= U_BUFFER_OVERFLOW_ERROR
) {
314 log_err("FAIL: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d: expected U_BUFFER_OVERFLOW_ERROR, got %s\n",
315 itemPtr
->locale
, (int)itemPtr
->width
, (int)itemPtr
->capContext
, myErrorName(status
) );
317 UChar ubufexp
[kUBufMax
];
318 int32_t ulenexp
= u_unescape(itemPtr
->expectedResult
, ubufexp
, kUBufMax
);
319 if (ulenget
!= ulenexp
) {
320 log_err("ERROR: ureldatefmt_combineDateAndTime() preflight for locale %s, width %d, capContext %d;\n expected len %d, get len %d\n",
321 itemPtr
->locale
, (int)itemPtr
->width
, (int)itemPtr
->capContext
, ulenexp
, ulenget
);
325 ureldatefmt_close(reldatefmt
);
329 #endif /* #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */