1/********************************************************************
2 * Copyright (c) 2008-2013, 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/tmunit.h"
11#include "unicode/tmutamt.h"
12#include "unicode/tmutfmt.h"
13#include "tufmtts.h"
14#include "unicode/ustring.h"
15
16//TODO: put as compilation flag
17//#define TUFMTTS_DEBUG 1
18
19#ifdef TUFMTTS_DEBUG
20#include <iostream>
21#endif
22
23void TimeUnitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
24    if (exec) logln("TestSuite TimeUnitTest");
25    switch (index) {
26        TESTCASE(0, testBasic);
27        TESTCASE(1, testAPI);
28        TESTCASE(2, testGreekWithFallback);
29        TESTCASE(3, testGreekWithSanitization);
30        default: name = ""; break;
31    }
32}
33
34/**
35 * Test basic
36 */
37void TimeUnitTest::testBasic() {
38    const char* locales[] = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant", "pa"};
39    for ( unsigned int locIndex = 0;
40          locIndex < sizeof(locales)/sizeof(locales[0]);
41          ++locIndex ) {
42        UErrorCode status = U_ZERO_ERROR;
43        Locale loc(locales[locIndex]);
44        TimeUnitFormat** formats = new TimeUnitFormat*[2];
45        formats[UTMUTFMT_FULL_STYLE] = new TimeUnitFormat(loc, status);
46        if (!assertSuccess("TimeUnitFormat(full)", status, TRUE)) return;
47        formats[UTMUTFMT_ABBREVIATED_STYLE] = new TimeUnitFormat(loc, UTMUTFMT_ABBREVIATED_STYLE, status);
48        if (!assertSuccess("TimeUnitFormat(short)", status)) return;
49#ifdef TUFMTTS_DEBUG
50        std::cout << "locale: " << locales[locIndex] << "\n";
51#endif
52        for (int style = UTMUTFMT_FULL_STYLE;
53             style <= UTMUTFMT_ABBREVIATED_STYLE;
54             ++style) {
55          for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
56             j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
57             j = (TimeUnit::UTimeUnitFields)(j+1)) {
58#ifdef TUFMTTS_DEBUG
59            std::cout << "time unit: " << j << "\n";
60#endif
61            double tests[] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35};
62            for (unsigned int i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
63#ifdef TUFMTTS_DEBUG
64                std::cout << "number: " << tests[i] << "\n";
65#endif
66                TimeUnitAmount* source = new TimeUnitAmount(tests[i], j, status);
67                if (!assertSuccess("TimeUnitAmount()", status)) return;
68                UnicodeString formatted;
69                Formattable formattable;
70                formattable.adoptObject(source);
71                formatted = ((Format*)formats[style])->format(formattable, formatted, status);
72                if (!assertSuccess("format()", status)) return;
73#ifdef TUFMTTS_DEBUG
74                char formatResult[1000];
75                formatted.extract(0, formatted.length(), formatResult, "UTF-8");
76                std::cout << "format result: " << formatResult << "\n";
77#endif
78                Formattable result;
79                ((Format*)formats[style])->parseObject(formatted, result, status);
80                if (!assertSuccess("parseObject()", status)) return;
81                if (result != formattable) {
82                    dataerrln("No round trip: ");
83                }
84                // other style parsing
85                Formattable result_1;
86                ((Format*)formats[1-style])->parseObject(formatted, result_1, status);
87                if (!assertSuccess("parseObject()", status)) return;
88                if (result_1 != formattable) {
89                    dataerrln("No round trip: ");
90                }
91            }
92          }
93        }
94        delete formats[UTMUTFMT_FULL_STYLE];
95        delete formats[UTMUTFMT_ABBREVIATED_STYLE];
96        delete[] formats;
97    }
98}
99
100
101void TimeUnitTest::testAPI() {
102    //================= TimeUnit =================
103    UErrorCode status = U_ZERO_ERROR;
104
105    TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status);
106    if (!assertSuccess("TimeUnit::createInstance", status)) return;
107
108    TimeUnit* another = (TimeUnit*)tmunit->clone();
109    TimeUnit third(*tmunit);
110    TimeUnit fourth = third;
111
112    assertTrue("orig and clone are equal", (*tmunit == *another));
113    assertTrue("copied and assigned are equal", (third == fourth));
114
115    TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status);
116    assertTrue("year != month", (*tmunit != *tmunit_m));
117
118    TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField();
119    assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH));
120
121    delete tmunit;
122    delete another;
123    delete tmunit_m;
124    //
125    //================= TimeUnitAmount =================
126
127    Formattable formattable((int32_t)2);
128    TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status);
129    if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
130
131    formattable.setDouble(2);
132    TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status);
133    if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
134
135    formattable.setDouble(3);
136    TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status);
137    if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
138
139    TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status);
140    if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
141
142    TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status);
143    if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
144
145    TimeUnitAmount second(tma);
146    TimeUnitAmount third_tma = tma;
147    TimeUnitAmount* fourth_tma = (TimeUnitAmount*)tma.clone();
148
149    assertTrue("orig and copy are equal", (second == tma));
150    assertTrue("clone and assigned are equal", (third_tma == *fourth_tma));
151    assertTrue("different if number diff", (tma_double != tma_double_3));
152    assertTrue("different if number type diff", (tma_double != tma_long));
153    assertTrue("different if time unit diff", (tma != tma_h));
154    assertTrue("same even different constructor", (tma_double == tma));
155
156    assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY));
157    delete fourth_tma;
158    //
159    //================= TimeUnitFormat =================
160    //
161    TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status);
162    if (!assertSuccess("TimeUnitFormat(en...)", status, TRUE)) return;
163    TimeUnitFormat tmf_fr(Locale("fr"), status);
164    if (!assertSuccess("TimeUnitFormat(fr...)", status)) return;
165
166    assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr));
167
168    TimeUnitFormat tmf_assign = *tmf_en;
169    assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign));
170
171    TimeUnitFormat tmf_copy(tmf_fr);
172    assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy));
173
174    TimeUnitFormat* tmf_clone = (TimeUnitFormat*)tmf_en->clone();
175    assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone));
176    delete tmf_clone;
177
178    tmf_en->setLocale(Locale("fr"), status);
179    if (!assertSuccess("setLocale(fr...)", status)) return;
180
181    NumberFormat* numberFmt = NumberFormat::createInstance(
182                                 Locale("fr"), status);
183    if (!assertSuccess("NumberFormat::createInstance()", status)) return;
184    tmf_en->setNumberFormat(*numberFmt, status);
185    if (!assertSuccess("setNumberFormat(en...)", status)) return;
186    assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr));
187
188    delete tmf_en;
189
190    TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), UTMUTFMT_FULL_STYLE, status);
191    if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
192    delete en_long;
193
194    TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), UTMUTFMT_ABBREVIATED_STYLE, status);
195    if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
196    delete en_short;
197
198    TimeUnitFormat* format = new TimeUnitFormat(status);
199    format->setLocale(Locale("zh"), status);
200    format->setNumberFormat(*numberFmt, status);
201    if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
202    delete numberFmt;
203    delete format;
204}
205
206/* @bug 7902
207 * Tests for Greek Language.
208 * This tests that requests for short unit names correctly fall back
209 * to long unit names for a locale where the locale data does not
210 * provide short unit names. As of CLDR 1.9, Greek is one such language.
211 */
212void TimeUnitTest::testGreekWithFallback() {
213    UErrorCode status = U_ZERO_ERROR;
214
215    const char* locales[] = {"el-GR", "el"};
216    TimeUnit::UTimeUnitFields tunits[] = {TimeUnit::UTIMEUNIT_SECOND, TimeUnit::UTIMEUNIT_MINUTE, TimeUnit::UTIMEUNIT_HOUR, TimeUnit::UTIMEUNIT_DAY, TimeUnit::UTIMEUNIT_MONTH, TimeUnit::UTIMEUNIT_YEAR};
217    UTimeUnitFormatStyle styles[] = {UTMUTFMT_FULL_STYLE, UTMUTFMT_ABBREVIATED_STYLE};
218    const int numbers[] = {1, 7};
219
220    const UChar oneSecond[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03bf, 0};
221    const UChar oneSecondShort[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
222    const UChar oneMinute[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03cc, 0};
223    const UChar oneMinuteShort[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
224    const UChar oneHour[] = {0x0031, 0x0020, 0x03ce, 0x03c1, 0x03b1, 0};
225    const UChar oneDay[] = {0x0031, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b1, 0};
226    const UChar oneMonth[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b1, 0x03c2, 0};
227    const UChar oneMonthShort[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
228    const UChar oneYear[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x03bf, 0x03c2, 0};
229    const UChar sevenSeconds[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03b1, 0};
230    const UChar sevenSecondsShort[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
231    const UChar sevenMinutes[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03ac, 0};
232    const UChar sevenMinutesShort[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
233    const UChar sevenHours[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x03b5, 0x03c2, 0};
234    const UChar sevenDays[] = {0x0037, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b5, 0x03c2, 0};
235    const UChar sevenMonths[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b5, 0x3c2, 0};
236    const UChar sevenMonthsShort[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
237    const UChar sevenYears[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x03b7, 0};
238
239    const UnicodeString oneSecondStr(oneSecond);
240    const UnicodeString oneSecondShortStr(oneSecondShort);
241    const UnicodeString oneMinuteStr(oneMinute);
242    const UnicodeString oneMinuteShortStr(oneMinuteShort);
243    const UnicodeString oneHourStr(oneHour);
244    const UnicodeString oneDayStr(oneDay);
245    const UnicodeString oneMonthStr(oneMonth);
246    const UnicodeString oneMonthShortStr(oneMonthShort);
247    const UnicodeString oneYearStr(oneYear);
248    const UnicodeString sevenSecondsStr(sevenSeconds);
249    const UnicodeString sevenSecondsShortStr(sevenSecondsShort);
250    const UnicodeString sevenMinutesStr(sevenMinutes);
251    const UnicodeString sevenMinutesShortStr(sevenMinutesShort);
252    const UnicodeString sevenHoursStr(sevenHours);
253    const UnicodeString sevenDaysStr(sevenDays);
254    const UnicodeString sevenMonthsStr(sevenMonths);
255    const UnicodeString sevenMonthsShortStr(sevenMonthsShort);
256    const UnicodeString sevenYearsStr(sevenYears);
257
258    const UnicodeString expected[] = {oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
259                              oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearStr,
260                              sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
261                              sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsStr,
262                              oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
263                              oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearStr,
264                              sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
265                              sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsStr};
266
267    int counter = 0;
268    for ( unsigned int locIndex = 0;
269        locIndex < sizeof(locales)/sizeof(locales[0]);
270        ++locIndex ) {
271
272        Locale l = Locale::createFromName(locales[locIndex]);
273
274        for ( unsigned int numberIndex = 0;
275            numberIndex < sizeof(numbers)/sizeof(int);
276            ++numberIndex ) {
277
278            for ( unsigned int styleIndex = 0;
279                styleIndex < sizeof(styles)/sizeof(styles[0]);
280                ++styleIndex ) {
281
282                for ( unsigned int unitIndex = 0;
283                    unitIndex < sizeof(tunits)/sizeof(tunits[0]);
284                    ++unitIndex ) {
285
286                    TimeUnitAmount *tamt = new TimeUnitAmount(numbers[numberIndex], tunits[unitIndex], status);
287                    if (U_FAILURE(status)) {
288                        dataerrln("generating TimeUnitAmount Object failed.");
289#ifdef TUFMTTS_DEBUG
290                        std::cout << "Failed to get TimeUnitAmount for " << tunits[unitIndex] << "\n";
291#endif
292                        return;
293                    }
294
295                    TimeUnitFormat *tfmt = new TimeUnitFormat(l, styles[styleIndex], status);
296                    if (U_FAILURE(status)) {
297                        dataerrln("generating TimeUnitAmount Object failed.");
298#ifdef TUFMTTS_DEBUG
299                       std::cout <<  "Failed to get TimeUnitFormat for " << locales[locIndex] << "\n";
300#endif
301                       return;
302                    }
303
304                    Formattable fmt;
305                    UnicodeString str;
306
307                    fmt.adoptObject(tamt);
308                    str = ((Format *)tfmt)->format(fmt, str, status);
309                    if (!assertSuccess("formatting relative time failed", status)) {
310                        delete tfmt;
311#ifdef TUFMTTS_DEBUG
312                        std::cout <<  "Failed to format" << "\n";
313#endif
314                        return;
315                    }
316
317#ifdef TUFMTTS_DEBUG
318                    char tmp[128];    //output
319                    char tmp1[128];    //expected
320                    int len = 0;
321                    u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status);
322                    u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status);
323                    std::cout <<  "Formatted string : " << tmp << " expected : " << tmp1 << "\n";
324#endif
325                    if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) {
326                        delete tfmt;
327                        str.remove();
328                        return;
329                    }
330                    delete tfmt;
331                    str.remove();
332                    ++counter;
333                }
334            }
335        }
336    }
337}
338
339// Test bug9042
340void TimeUnitTest::testGreekWithSanitization() {
341
342    UErrorCode status = U_ZERO_ERROR;
343    Locale elLoc("el");
344    NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status);
345    if (!assertSuccess("NumberFormat::createInstance for el locale", status, TRUE)) return;
346    numberFmt->setMaximumFractionDigits(1);
347
348    TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status);
349    if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return;
350
351    timeUnitFormat->setNumberFormat(*numberFmt, status);
352
353    delete numberFmt;
354    delete timeUnitFormat;
355}
356
357#endif
358