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
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)26 void 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
tmaEqual(const TimeUnitAmount & left,const TimeUnitAmount & right)40 static 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 */
testBasic()58 void 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
testAPI()122 void 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 */
testGreekWithFallback()262 void 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
testGreekWithSanitization()390 void 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
test10219Plurals()407 void 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