• 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*/ ) 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