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