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