1// Copyright (C) 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 27class TimeUnitTest : public IntlTest { 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 40public: 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 79extern 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 85static 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 */ 103void 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 167void 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 */ 307void 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 443void 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 460void 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 518void 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