1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * Copyright (c) 2008-2016, International Business Machines Corporation and
5 * others. All Rights Reserved.
6 ********************************************************************/
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_FORMATTING
11
12 #include "unicode/decimfmt.h"
13 #include "unicode/tmunit.h"
14 #include "unicode/tmutamt.h"
15 #include "unicode/tmutfmt.h"
16 #include "unicode/ustring.h"
17 #include "cmemory.h"
18 #include "intltest.h"
19
20 //TODO: put as compilation flag
21 //#define TUFMTTS_DEBUG 1
22
23 #ifdef TUFMTTS_DEBUG
24 #include <iostream>
25 #endif
26
27 class TimeUnitTest : public IntlTest {
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)28 void runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
29 if (exec) logln("TestSuite TimeUnitTest");
30 TESTCASE_AUTO_BEGIN;
31 TESTCASE_AUTO(testBasic);
32 TESTCASE_AUTO(testAPI);
33 TESTCASE_AUTO(testGreekWithFallback);
34 TESTCASE_AUTO(testGreekWithSanitization);
35 TESTCASE_AUTO(test10219Plurals);
36 TESTCASE_AUTO(TestBritishShortHourFallback);
37 TESTCASE_AUTO_END;
38 }
39
40 public:
41 /**
42 * Performs basic tests
43 **/
44 void testBasic();
45
46 /**
47 * Performs API tests
48 **/
49 void testAPI();
50
51 /**
52 * Performs tests for Greek
53 * This tests that requests for short unit names correctly fall back
54 * to long unit names for a locale where the locale data does not
55 * provide short unit names. As of CLDR 1.9, Greek is one such language.
56 **/
57 void testGreekWithFallback();
58
59 /**
60 * Performs tests for Greek
61 * This tests that if the plural count listed in time unit format does not
62 * match those in the plural rules for the locale, those plural count in
63 * time unit format will be ingored and subsequently, fall back will kick in
64 * which is tested above.
65 * Without data sanitization, setNumberFormat() would crash.
66 * As of CLDR shiped in ICU4.8, Greek is one such language.
67 */
68 void testGreekWithSanitization();
69
70 /**
71 * Performs unit test for ticket 10219 making sure that plurals work
72 * correctly with rounding.
73 */
74 void test10219Plurals();
75
76 void TestBritishShortHourFallback();
77 };
78
createTimeUnitTest()79 extern IntlTest *createTimeUnitTest() {
80 return new TimeUnitTest();
81 }
82
83 // This function is more lenient than equals operator as it considers integer 3 hours and
84 // double 3.0 hours to be equal
tmaEqual(const TimeUnitAmount & left,const TimeUnitAmount & right)85 static UBool tmaEqual(const TimeUnitAmount& left, const TimeUnitAmount& right) {
86 if (left.getTimeUnitField() != right.getTimeUnitField()) {
87 return FALSE;
88 }
89 UErrorCode status = U_ZERO_ERROR;
90 if (!left.getNumber().isNumeric() || !right.getNumber().isNumeric()) {
91 return FALSE;
92 }
93 UBool result = left.getNumber().getDouble(status) == right.getNumber().getDouble(status);
94 if (U_FAILURE(status)) {
95 return FALSE;
96 }
97 return result;
98 }
99
100 /**
101 * Test basic
102 */
testBasic()103 void TimeUnitTest::testBasic() {
104 const char* locales[] = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant", "pa"};
105 for ( unsigned int locIndex = 0;
106 locIndex < UPRV_LENGTHOF(locales);
107 ++locIndex ) {
108 UErrorCode status = U_ZERO_ERROR;
109 Locale loc(locales[locIndex]);
110 TimeUnitFormat** formats = new TimeUnitFormat*[2];
111 formats[UTMUTFMT_FULL_STYLE] = new TimeUnitFormat(loc, status);
112 if (!assertSuccess("TimeUnitFormat(full)", status, TRUE)) return;
113 formats[UTMUTFMT_ABBREVIATED_STYLE] = new TimeUnitFormat(loc, UTMUTFMT_ABBREVIATED_STYLE, status);
114 if (!assertSuccess("TimeUnitFormat(short)", status)) return;
115 #ifdef TUFMTTS_DEBUG
116 std::cout << "locale: " << locales[locIndex] << "\n";
117 #endif
118 for (int style = UTMUTFMT_FULL_STYLE;
119 style <= UTMUTFMT_ABBREVIATED_STYLE;
120 ++style) {
121 for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
122 j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
123 j = (TimeUnit::UTimeUnitFields)(j+1)) {
124 #ifdef TUFMTTS_DEBUG
125 std::cout << "time unit: " << j << "\n";
126 #endif
127 double tests[] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35};
128 for (unsigned int i = 0; i < UPRV_LENGTHOF(tests); ++i) {
129 #ifdef TUFMTTS_DEBUG
130 std::cout << "number: " << tests[i] << "\n";
131 #endif
132 TimeUnitAmount* source = new TimeUnitAmount(tests[i], j, status);
133 if (!assertSuccess("TimeUnitAmount()", status)) return;
134 UnicodeString formatted;
135 Formattable formattable;
136 formattable.adoptObject(source);
137 formatted = ((Format*)formats[style])->format(formattable, formatted, status);
138 if (!assertSuccess("format()", status)) return;
139 #ifdef TUFMTTS_DEBUG
140 char formatResult[1000];
141 formatted.extract(0, formatted.length(), formatResult, "UTF-8");
142 std::cout << "format result: " << formatResult << "\n";
143 #endif
144 Formattable result;
145 ((Format*)formats[style])->parseObject(formatted, result, status);
146 if (!assertSuccess("parseObject()", status)) return;
147 if (!tmaEqual(*((TimeUnitAmount *)result.getObject()), *((TimeUnitAmount *) formattable.getObject()))) {
148 dataerrln("No round trip: ");
149 }
150 // other style parsing
151 Formattable result_1;
152 ((Format*)formats[1-style])->parseObject(formatted, result_1, status);
153 if (!assertSuccess("parseObject()", status)) return;
154 if (!tmaEqual(*((TimeUnitAmount *)result_1.getObject()), *((TimeUnitAmount *) formattable.getObject()))) {
155 dataerrln("No round trip: ");
156 }
157 }
158 }
159 }
160 delete formats[UTMUTFMT_FULL_STYLE];
161 delete formats[UTMUTFMT_ABBREVIATED_STYLE];
162 delete[] formats;
163 }
164 }
165
166
testAPI()167 void TimeUnitTest::testAPI() {
168 //================= TimeUnit =================
169 UErrorCode status = U_ZERO_ERROR;
170
171 TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status);
172 if (!assertSuccess("TimeUnit::createInstance", status)) return;
173
174 TimeUnit* another = tmunit->clone();
175 TimeUnit third(*tmunit);
176 TimeUnit fourth = third;
177
178 assertTrue("orig and clone are equal", (*tmunit == *another));
179 assertTrue("copied and assigned are equal", (third == fourth));
180
181 TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status);
182 assertTrue("year != month", (*tmunit != *tmunit_m));
183
184 TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField();
185 assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH));
186
187 //===== Interoperability with MeasureUnit ======
188 MeasureUnit **ptrs = new MeasureUnit *[TimeUnit::UTIMEUNIT_FIELD_COUNT];
189
190 ptrs[TimeUnit::UTIMEUNIT_YEAR] = MeasureUnit::createYear(status);
191 ptrs[TimeUnit::UTIMEUNIT_MONTH] = MeasureUnit::createMonth(status);
192 ptrs[TimeUnit::UTIMEUNIT_DAY] = MeasureUnit::createDay(status);
193 ptrs[TimeUnit::UTIMEUNIT_WEEK] = MeasureUnit::createWeek(status);
194 ptrs[TimeUnit::UTIMEUNIT_HOUR] = MeasureUnit::createHour(status);
195 ptrs[TimeUnit::UTIMEUNIT_MINUTE] = MeasureUnit::createMinute(status);
196 ptrs[TimeUnit::UTIMEUNIT_SECOND] = MeasureUnit::createSecond(status);
197 if (!assertSuccess("TimeUnit::createInstance", status)) return;
198
199 for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
200 j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
201 j = (TimeUnit::UTimeUnitFields)(j+1)) {
202 MeasureUnit *ptr = TimeUnit::createInstance(j, status);
203 if (!assertSuccess("TimeUnit::createInstance", status)) return;
204 // We have to convert *ptr to a MeasureUnit or else == will fail over
205 // differing types (TimeUnit vs. MeasureUnit).
206 assertTrue(
207 "Time unit should be equal to corresponding MeasureUnit",
208 MeasureUnit(*ptr) == *ptrs[j]);
209 delete ptr;
210 }
211 delete tmunit;
212 delete another;
213 delete tmunit_m;
214 for (int i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
215 delete ptrs[i];
216 }
217 delete [] ptrs;
218
219 //
220 //================= TimeUnitAmount =================
221
222 Formattable formattable((int32_t)2);
223 TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status);
224 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
225
226 formattable.setDouble(2);
227 TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status);
228 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
229
230 formattable.setDouble(3);
231 TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status);
232 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
233
234 TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status);
235 if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
236
237 TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status);
238 if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
239
240 TimeUnitAmount second(tma);
241 TimeUnitAmount third_tma = tma;
242 TimeUnitAmount* fourth_tma = tma.clone();
243
244 assertTrue("orig and copy are equal", (second == tma));
245 assertTrue("clone and assigned are equal", (third_tma == *fourth_tma));
246 assertTrue("different if number diff", (tma_double != tma_double_3));
247 assertTrue("different if number type diff", (tma_double != tma_long));
248 assertTrue("different if time unit diff", (tma != tma_h));
249 assertTrue("same even different constructor", (tma_double == tma));
250
251 assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY));
252 delete fourth_tma;
253 //
254 //================= TimeUnitFormat =================
255 //
256 TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status);
257 if (!assertSuccess("TimeUnitFormat(en...)", status, TRUE)) return;
258 TimeUnitFormat tmf_fr(Locale("fr"), status);
259 if (!assertSuccess("TimeUnitFormat(fr...)", status)) return;
260
261 assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr));
262
263 TimeUnitFormat tmf_assign = *tmf_en;
264 assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign));
265
266 TimeUnitFormat tmf_copy(tmf_fr);
267 assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy));
268
269 TimeUnitFormat* tmf_clone = tmf_en->clone();
270 assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone));
271 delete tmf_clone;
272
273 tmf_en->setLocale(Locale("fr"), status);
274 if (!assertSuccess("setLocale(fr...)", status)) return;
275
276 NumberFormat* numberFmt = NumberFormat::createInstance(
277 Locale("fr"), status);
278 if (!assertSuccess("NumberFormat::createInstance()", status)) return;
279 tmf_en->setNumberFormat(*numberFmt, status);
280 if (!assertSuccess("setNumberFormat(en...)", status)) return;
281 assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr));
282
283 delete tmf_en;
284
285 TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), UTMUTFMT_FULL_STYLE, status);
286 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
287 delete en_long;
288
289 TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), UTMUTFMT_ABBREVIATED_STYLE, status);
290 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
291 delete en_short;
292
293 TimeUnitFormat* format = new TimeUnitFormat(status);
294 format->setLocale(Locale("zh"), status);
295 format->setNumberFormat(*numberFmt, status);
296 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
297 delete numberFmt;
298 delete format;
299 }
300
301 /* @bug 7902
302 * Tests for Greek Language.
303 * This tests that requests for short unit names correctly fall back
304 * to long unit names for a locale where the locale data does not
305 * provide short unit names. As of CLDR 1.9, Greek is one such language.
306 */
testGreekWithFallback()307 void TimeUnitTest::testGreekWithFallback() {
308 UErrorCode status = U_ZERO_ERROR;
309
310 const char* locales[] = {"el-GR", "el"};
311 TimeUnit::UTimeUnitFields tunits[] = {TimeUnit::UTIMEUNIT_SECOND, TimeUnit::UTIMEUNIT_MINUTE, TimeUnit::UTIMEUNIT_HOUR, TimeUnit::UTIMEUNIT_DAY, TimeUnit::UTIMEUNIT_MONTH, TimeUnit::UTIMEUNIT_YEAR};
312 UTimeUnitFormatStyle styles[] = {UTMUTFMT_FULL_STYLE, UTMUTFMT_ABBREVIATED_STYLE};
313 const int numbers[] = {1, 7};
314
315 const UChar oneSecond[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03bf, 0};
316 const UChar oneSecondShort[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
317 const UChar oneMinute[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03cc, 0};
318 const UChar oneMinuteShort[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
319 const UChar oneHour[] = {0x0031, 0x0020, 0x03ce, 0x03c1, 0x03b1, 0};
320 const UChar oneDay[] = {0x0031, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b1, 0};
321 const UChar oneMonth[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b1, 0x03c2, 0};
322 const UChar oneMonthShort[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
323 const UChar oneYear[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x03bf, 0x03c2, 0};
324 const UChar oneYearShort[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
325 const UChar sevenSeconds[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03b1, 0};
326 const UChar sevenSecondsShort[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
327 const UChar sevenMinutes[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03ac, 0};
328 const UChar sevenMinutesShort[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
329 const UChar sevenHours[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x03b5, 0x03c2, 0};
330 const UChar sevenHoursShort[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x002e, 0};
331 const UChar sevenDays[] = {0x0037, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b5, 0x03c2, 0};
332 const UChar sevenMonths[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b5, 0x3c2, 0};
333 const UChar sevenMonthsShort[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
334 const UChar sevenYears[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x03b7, 0};
335 const UChar sevenYearsShort[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
336
337 const UnicodeString oneSecondStr(oneSecond);
338 const UnicodeString oneSecondShortStr(oneSecondShort);
339 const UnicodeString oneMinuteStr(oneMinute);
340 const UnicodeString oneMinuteShortStr(oneMinuteShort);
341 const UnicodeString oneHourStr(oneHour);
342 const UnicodeString oneDayStr(oneDay);
343 const UnicodeString oneMonthStr(oneMonth);
344 const UnicodeString oneMonthShortStr(oneMonthShort);
345 const UnicodeString oneYearStr(oneYear);
346 const UnicodeString oneYearShortStr(oneYearShort);
347 const UnicodeString sevenSecondsStr(sevenSeconds);
348 const UnicodeString sevenSecondsShortStr(sevenSecondsShort);
349 const UnicodeString sevenMinutesStr(sevenMinutes);
350 const UnicodeString sevenMinutesShortStr(sevenMinutesShort);
351 const UnicodeString sevenHoursStr(sevenHours);
352 const UnicodeString sevenHoursShortStr(sevenHoursShort);
353 const UnicodeString sevenDaysStr(sevenDays);
354 const UnicodeString sevenMonthsStr(sevenMonths);
355 const UnicodeString sevenMonthsShortStr(sevenMonthsShort);
356 const UnicodeString sevenYearsStr(sevenYears);
357 const UnicodeString sevenYearsShortStr(sevenYearsShort);
358
359 const UnicodeString expected[] = {
360 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
361 oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
362 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
363 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr,
364
365 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
366 oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
367 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
368 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr};
369
370 int counter = 0;
371 for ( unsigned int locIndex = 0;
372 locIndex < UPRV_LENGTHOF(locales);
373 ++locIndex ) {
374
375 Locale l = Locale::createFromName(locales[locIndex]);
376
377 for ( unsigned int numberIndex = 0;
378 numberIndex < UPRV_LENGTHOF(numbers);
379 ++numberIndex ) {
380
381 for ( unsigned int styleIndex = 0;
382 styleIndex < UPRV_LENGTHOF(styles);
383 ++styleIndex ) {
384
385 for ( unsigned int unitIndex = 0;
386 unitIndex < UPRV_LENGTHOF(tunits);
387 ++unitIndex ) {
388
389 LocalPointer<TimeUnitAmount>tamt(new TimeUnitAmount(numbers[numberIndex], tunits[unitIndex], status));
390 if (U_FAILURE(status)) {
391 dataerrln("generating TimeUnitAmount Object failed.");
392 #ifdef TUFMTTS_DEBUG
393 std::cout << "Failed to get TimeUnitAmount for " << tunits[unitIndex] << "\n";
394 #endif
395 return;
396 }
397
398 LocalPointer<TimeUnitFormat> tfmt(new TimeUnitFormat(l, styles[styleIndex], status));
399 if (U_FAILURE(status)) {
400 dataerrln("generating TimeUnitAmount Object failed.");
401 #ifdef TUFMTTS_DEBUG
402 std::cout << "Failed to get TimeUnitFormat for " << locales[locIndex] << "\n";
403 #endif
404 return;
405 }
406
407 Formattable fmt;
408 UnicodeString str;
409
410 fmt.adoptObject(tamt.orphan());
411 str = ((Format *)tfmt.getAlias())->format(fmt, str, status);
412 if (!assertSuccess("formatting relative time failed", status)) {
413 #ifdef TUFMTTS_DEBUG
414 std::cout << "Failed to format" << "\n";
415 #endif
416 return;
417 }
418
419 #ifdef TUFMTTS_DEBUG
420 char tmp[128]; //output
421 char tmp1[128]; //expected
422 int len = 0;
423 u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status);
424 u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status);
425 std::cout << "Formatted string : " << tmp << " expected : " << tmp1 << "\n";
426 #endif
427 if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) {
428 str.remove();
429 return;
430 }
431 str.remove();
432 ++counter;
433 }
434 }
435 }
436 }
437 }
438
439 // Test bug9042
testGreekWithSanitization()440 void TimeUnitTest::testGreekWithSanitization() {
441
442 UErrorCode status = U_ZERO_ERROR;
443 Locale elLoc("el");
444 NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status);
445 if (!assertSuccess("NumberFormat::createInstance for el locale", status, TRUE)) return;
446 numberFmt->setMaximumFractionDigits(1);
447
448 TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status);
449 if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return;
450
451 timeUnitFormat->setNumberFormat(*numberFmt, status);
452
453 delete numberFmt;
454 delete timeUnitFormat;
455 }
456
test10219Plurals()457 void TimeUnitTest::test10219Plurals() {
458 Locale usLocale("en_US");
459 double values[2] = {1.588, 1.011};
460 UnicodeString expected[2][3] = {
461 {"1 minute", "1.5 minutes", "1.58 minutes"},
462 {"1 minute", "1.0 minutes", "1.01 minutes"}
463 };
464 UErrorCode status = U_ZERO_ERROR;
465 TimeUnitFormat tuf(usLocale, status);
466 if (U_FAILURE(status)) {
467 dataerrln("generating TimeUnitFormat Object failed: %s", u_errorName(status));
468 return;
469 }
470 LocalPointer<DecimalFormat> nf((DecimalFormat *) NumberFormat::createInstance(usLocale, status));
471 if (U_FAILURE(status)) {
472 dataerrln("generating NumberFormat Object failed: %s", u_errorName(status));
473 return;
474 }
475 for (int32_t j = 0; j < UPRV_LENGTHOF(values); ++j) {
476 for (int32_t i = 0; i < UPRV_LENGTHOF(expected[j]); ++i) {
477 nf->setMinimumFractionDigits(i);
478 nf->setMaximumFractionDigits(i);
479 nf->setRoundingMode(DecimalFormat::kRoundDown);
480 tuf.setNumberFormat(*nf, status);
481 if (U_FAILURE(status)) {
482 dataerrln("setting NumberFormat failed: %s", u_errorName(status));
483 return;
484 }
485 UnicodeString actual;
486 Formattable fmt;
487 LocalPointer<TimeUnitAmount> tamt(
488 new TimeUnitAmount(values[j], TimeUnit::UTIMEUNIT_MINUTE, status), status);
489 if (U_FAILURE(status)) {
490 dataerrln("generating TimeUnitAmount Object failed: %s", u_errorName(status));
491 return;
492 }
493 fmt.adoptObject(tamt.orphan());
494 tuf.format(fmt, actual, status);
495 if (U_FAILURE(status)) {
496 dataerrln("Actual formatting failed: %s", u_errorName(status));
497 return;
498 }
499 if (expected[j][i] != actual) {
500 errln("Expected " + expected[j][i] + ", got " + actual);
501 }
502 }
503 }
504
505 // test parsing
506 Formattable result;
507 ParsePosition pos;
508 UnicodeString formattedString = "1 minutes";
509 tuf.parseObject(formattedString, result, pos);
510 if (formattedString.length() != pos.getIndex()) {
511 errln("Expect parsing to go all the way to the end of the string.");
512 }
513 }
514
TestBritishShortHourFallback()515 void TimeUnitTest::TestBritishShortHourFallback() {
516 // See ticket #11986 "incomplete fallback in MeasureFormat".
517 UErrorCode status = U_ZERO_ERROR;
518 Formattable oneHour(new TimeUnitAmount(1, TimeUnit::UTIMEUNIT_HOUR, status));
519 Locale en_GB("en_GB");
520 TimeUnitFormat formatter(en_GB, UTMUTFMT_ABBREVIATED_STYLE, status);
521 UnicodeString result;
522 formatter.format(oneHour, result, status);
523 assertSuccess("TestBritishShortHourFallback()", status);
524 assertEquals("TestBritishShortHourFallback()", UNICODE_STRING_SIMPLE("1 hr"), result, TRUE);
525 }
526
527 #endif
528