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