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*/ ) override {
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 ignored and subsequently, fall back will kick in
64 * which is tested above.
65 * Without data sanitization, setNumberFormat() would crash.
66 * As of CLDR shipped 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, 0x002e, 0};
319 const UChar oneHour[] = {0x0031, 0x0020, 0x03ce, 0x03c1, 0x03b1, 0};
320 const UChar oneHourShort[] = {0x0031, 0x0020, 0x03ce, 0x002e, 0};
321 const UChar oneDay[] = {0x0031, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b1, 0};
322 const UChar oneMonth[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b1, 0x03c2, 0};
323 const UChar oneMonthShort[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
324 const UChar oneYear[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x03bf, 0x03c2, 0};
325 const UChar oneYearShort[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
326 const UChar sevenSeconds[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03b1, 0};
327 const UChar sevenSecondsShort[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
328 const UChar sevenMinutes[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03ac, 0};
329 const UChar sevenMinutesShort[] = {0x0037, 0x0020, 0x03bb, 0x002e, 0};
330 const UChar sevenHours[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x03b5, 0x03c2, 0};
331 const UChar sevenHoursShort[] = {0x0037, 0x0020, 0x03ce, 0x002e, 0};
332 const UChar sevenDays[] = {0x0037, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b5, 0x03c2, 0};
333 const UChar sevenMonths[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b5, 0x3c2, 0};
334 const UChar sevenMonthsShort[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
335 const UChar sevenYears[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x03b7, 0};
336 const UChar sevenYearsShort[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
337
338 const UnicodeString oneSecondStr(oneSecond);
339 const UnicodeString oneSecondShortStr(oneSecondShort);
340 const UnicodeString oneMinuteStr(oneMinute);
341 const UnicodeString oneMinuteShortStr(oneMinuteShort);
342 const UnicodeString oneHourStr(oneHour);
343 const UnicodeString oneHourShortStr(oneHourShort);
344 const UnicodeString oneDayStr(oneDay);
345 const UnicodeString oneMonthStr(oneMonth);
346 const UnicodeString oneMonthShortStr(oneMonthShort);
347 const UnicodeString oneYearStr(oneYear);
348 const UnicodeString oneYearShortStr(oneYearShort);
349 const UnicodeString sevenSecondsStr(sevenSeconds);
350 const UnicodeString sevenSecondsShortStr(sevenSecondsShort);
351 const UnicodeString sevenMinutesStr(sevenMinutes);
352 const UnicodeString sevenMinutesShortStr(sevenMinutesShort);
353 const UnicodeString sevenHoursStr(sevenHours);
354 const UnicodeString sevenHoursShortStr(sevenHoursShort);
355 const UnicodeString sevenDaysStr(sevenDays);
356 const UnicodeString sevenMonthsStr(sevenMonths);
357 const UnicodeString sevenMonthsShortStr(sevenMonthsShort);
358 const UnicodeString sevenYearsStr(sevenYears);
359 const UnicodeString sevenYearsShortStr(sevenYearsShort);
360
361 const UnicodeString expected[] = {
362 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
363 oneSecondShortStr, oneMinuteShortStr, oneHourShortStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
364 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
365 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr,
366
367 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
368 oneSecondShortStr, oneMinuteShortStr, oneHourShortStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
369 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
370 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr};
371
372 int counter = 0;
373 for ( unsigned int locIndex = 0;
374 locIndex < UPRV_LENGTHOF(locales);
375 ++locIndex ) {
376
377 Locale l = Locale::createFromName(locales[locIndex]);
378
379 for ( unsigned int numberIndex = 0;
380 numberIndex < UPRV_LENGTHOF(numbers);
381 ++numberIndex ) {
382
383 for ( unsigned int styleIndex = 0;
384 styleIndex < UPRV_LENGTHOF(styles);
385 ++styleIndex ) {
386
387 for ( unsigned int unitIndex = 0;
388 unitIndex < UPRV_LENGTHOF(tunits);
389 ++unitIndex ) {
390
391 LocalPointer<TimeUnitAmount>tamt(new TimeUnitAmount(numbers[numberIndex], tunits[unitIndex], status));
392 if (U_FAILURE(status)) {
393 dataerrln("generating TimeUnitAmount Object failed.");
394 #ifdef TUFMTTS_DEBUG
395 std::cout << "Failed to get TimeUnitAmount for " << tunits[unitIndex] << "\n";
396 #endif
397 return;
398 }
399
400 LocalPointer<TimeUnitFormat> tfmt(new TimeUnitFormat(l, styles[styleIndex], status));
401 if (U_FAILURE(status)) {
402 dataerrln("generating TimeUnitAmount Object failed.");
403 #ifdef TUFMTTS_DEBUG
404 std::cout << "Failed to get TimeUnitFormat for " << locales[locIndex] << "\n";
405 #endif
406 return;
407 }
408
409 Formattable fmt;
410 UnicodeString str;
411
412 fmt.adoptObject(tamt.orphan());
413 str = ((Format *)tfmt.getAlias())->format(fmt, str, status);
414 if (!assertSuccess("formatting relative time failed", status)) {
415 #ifdef TUFMTTS_DEBUG
416 std::cout << "Failed to format" << "\n";
417 #endif
418 return;
419 }
420
421 #ifdef TUFMTTS_DEBUG
422 char tmp[128]; //output
423 char tmp1[128]; //expected
424 int len = 0;
425 u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status);
426 u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status);
427 std::cout << "Formatted string : " << tmp << " expected : " << tmp1 << "\n";
428 #endif
429 if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) {
430 str.remove();
431 return;
432 }
433 str.remove();
434 ++counter;
435 }
436 }
437 }
438 }
439 }
440
441 // Test bug9042
testGreekWithSanitization()442 void TimeUnitTest::testGreekWithSanitization() {
443
444 UErrorCode status = U_ZERO_ERROR;
445 Locale elLoc("el");
446 NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status);
447 if (!assertSuccess("NumberFormat::createInstance for el locale", status, true)) return;
448 numberFmt->setMaximumFractionDigits(1);
449
450 TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status);
451 if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return;
452
453 timeUnitFormat->setNumberFormat(*numberFmt, status);
454
455 delete numberFmt;
456 delete timeUnitFormat;
457 }
458
test10219Plurals()459 void TimeUnitTest::test10219Plurals() {
460 Locale usLocale("en_US");
461 double values[2] = {1.588, 1.011};
462 UnicodeString expected[2][3] = {
463 {"1 minute", "1.5 minutes", "1.58 minutes"},
464 {"1 minute", "1.0 minutes", "1.01 minutes"}
465 };
466 UErrorCode status = U_ZERO_ERROR;
467 TimeUnitFormat tuf(usLocale, status);
468 if (U_FAILURE(status)) {
469 dataerrln("generating TimeUnitFormat Object failed: %s", u_errorName(status));
470 return;
471 }
472 LocalPointer<DecimalFormat> nf((DecimalFormat *) NumberFormat::createInstance(usLocale, status));
473 if (U_FAILURE(status)) {
474 dataerrln("generating NumberFormat Object failed: %s", u_errorName(status));
475 return;
476 }
477 for (int32_t j = 0; j < UPRV_LENGTHOF(values); ++j) {
478 for (int32_t i = 0; i < UPRV_LENGTHOF(expected[j]); ++i) {
479 nf->setMinimumFractionDigits(i);
480 nf->setMaximumFractionDigits(i);
481 nf->setRoundingMode(DecimalFormat::kRoundDown);
482 tuf.setNumberFormat(*nf, status);
483 if (U_FAILURE(status)) {
484 dataerrln("setting NumberFormat failed: %s", u_errorName(status));
485 return;
486 }
487 UnicodeString actual;
488 Formattable fmt;
489 LocalPointer<TimeUnitAmount> tamt(
490 new TimeUnitAmount(values[j], TimeUnit::UTIMEUNIT_MINUTE, status), status);
491 if (U_FAILURE(status)) {
492 dataerrln("generating TimeUnitAmount Object failed: %s", u_errorName(status));
493 return;
494 }
495 fmt.adoptObject(tamt.orphan());
496 tuf.format(fmt, actual, status);
497 if (U_FAILURE(status)) {
498 dataerrln("Actual formatting failed: %s", u_errorName(status));
499 return;
500 }
501 if (expected[j][i] != actual) {
502 errln("Expected " + expected[j][i] + ", got " + actual);
503 }
504 }
505 }
506
507 // test parsing
508 Formattable result;
509 ParsePosition pos;
510 UnicodeString formattedString = "1 minutes";
511 tuf.parseObject(formattedString, result, pos);
512 if (formattedString.length() != pos.getIndex()) {
513 errln("Expect parsing to go all the way to the end of the string.");
514 }
515 }
516
TestBritishShortHourFallback()517 void TimeUnitTest::TestBritishShortHourFallback() {
518 // See ticket #11986 "incomplete fallback in MeasureFormat".
519 UErrorCode status = U_ZERO_ERROR;
520 Formattable oneHour(new TimeUnitAmount(1, TimeUnit::UTIMEUNIT_HOUR, status));
521 Locale en_GB("en_GB");
522 TimeUnitFormat formatter(en_GB, UTMUTFMT_ABBREVIATED_STYLE, status);
523 UnicodeString result;
524 formatter.format(oneHour, result, status);
525 assertSuccess("TestBritishShortHourFallback()", status);
526 assertEquals("TestBritishShortHourFallback()", UNICODE_STRING_SIMPLE("1 hr"), result, true);
527 }
528
529 #endif
530