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 = (TimeUnit*)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 = (TimeUnitAmount*)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 = (TimeUnitFormat*)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 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 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);
411 str = ((Format *)tfmt)->format(fmt, str, status);
412 if (!assertSuccess("formatting relative time failed", status)) {
413 delete tfmt;
414 #ifdef TUFMTTS_DEBUG
415 std::cout << "Failed to format" << "\n";
416 #endif
417 return;
418 }
419
420 #ifdef TUFMTTS_DEBUG
421 char tmp[128]; //output
422 char tmp1[128]; //expected
423 int len = 0;
424 u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status);
425 u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status);
426 std::cout << "Formatted string : " << tmp << " expected : " << tmp1 << "\n";
427 #endif
428 if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) {
429 delete tfmt;
430 str.remove();
431 return;
432 }
433 delete tfmt;
434 str.remove();
435 ++counter;
436 }
437 }
438 }
439 }
440 }
441
442 // Test bug9042
testGreekWithSanitization()443 void TimeUnitTest::testGreekWithSanitization() {
444
445 UErrorCode status = U_ZERO_ERROR;
446 Locale elLoc("el");
447 NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status);
448 if (!assertSuccess("NumberFormat::createInstance for el locale", status, TRUE)) return;
449 numberFmt->setMaximumFractionDigits(1);
450
451 TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status);
452 if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return;
453
454 timeUnitFormat->setNumberFormat(*numberFmt, status);
455
456 delete numberFmt;
457 delete timeUnitFormat;
458 }
459
test10219Plurals()460 void TimeUnitTest::test10219Plurals() {
461 Locale usLocale("en_US");
462 double values[2] = {1.588, 1.011};
463 UnicodeString expected[2][3] = {
464 {"1 minute", "1.5 minutes", "1.58 minutes"},
465 {"1 minute", "1.0 minutes", "1.01 minutes"}
466 };
467 UErrorCode status = U_ZERO_ERROR;
468 TimeUnitFormat tuf(usLocale, status);
469 if (U_FAILURE(status)) {
470 dataerrln("generating TimeUnitFormat Object failed: %s", u_errorName(status));
471 return;
472 }
473 LocalPointer<DecimalFormat> nf((DecimalFormat *) NumberFormat::createInstance(usLocale, status));
474 if (U_FAILURE(status)) {
475 dataerrln("generating NumberFormat Object failed: %s", u_errorName(status));
476 return;
477 }
478 for (int32_t j = 0; j < UPRV_LENGTHOF(values); ++j) {
479 for (int32_t i = 0; i < UPRV_LENGTHOF(expected[j]); ++i) {
480 nf->setMinimumFractionDigits(i);
481 nf->setMaximumFractionDigits(i);
482 nf->setRoundingMode(DecimalFormat::kRoundDown);
483 tuf.setNumberFormat(*nf, status);
484 if (U_FAILURE(status)) {
485 dataerrln("setting NumberFormat failed: %s", u_errorName(status));
486 return;
487 }
488 UnicodeString actual;
489 Formattable fmt;
490 LocalPointer<TimeUnitAmount> tamt(
491 new TimeUnitAmount(values[j], TimeUnit::UTIMEUNIT_MINUTE, status), status);
492 if (U_FAILURE(status)) {
493 dataerrln("generating TimeUnitAmount Object failed: %s", u_errorName(status));
494 return;
495 }
496 fmt.adoptObject(tamt.orphan());
497 tuf.format(fmt, actual, status);
498 if (U_FAILURE(status)) {
499 dataerrln("Actual formatting failed: %s", u_errorName(status));
500 return;
501 }
502 if (expected[j][i] != actual) {
503 errln("Expected " + expected[j][i] + ", got " + actual);
504 }
505 }
506 }
507
508 // test parsing
509 Formattable result;
510 ParsePosition pos;
511 UnicodeString formattedString = "1 minutes";
512 tuf.parseObject(formattedString, result, pos);
513 if (formattedString.length() != pos.getIndex()) {
514 errln("Expect parsing to go all the way to the end of the string.");
515 }
516 }
517
TestBritishShortHourFallback()518 void TimeUnitTest::TestBritishShortHourFallback() {
519 // See ticket #11986 "incomplete fallback in MeasureFormat".
520 UErrorCode status = U_ZERO_ERROR;
521 Formattable oneHour(new TimeUnitAmount(1, TimeUnit::UTIMEUNIT_HOUR, status));
522 Locale en_GB("en_GB");
523 TimeUnitFormat formatter(en_GB, UTMUTFMT_ABBREVIATED_STYLE, status);
524 UnicodeString result;
525 formatter.format(oneHour, result, status);
526 assertSuccess("TestBritishShortHourFallback()", status);
527 assertEquals("TestBritishShortHourFallback()", UNICODE_STRING_SIMPLE("1 hr"), result, TRUE);
528 }
529
530 #endif
531