• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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