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