1/***********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ***********************************************************************/
6
7#include "unicode/utypes.h"
8
9#if !UCONFIG_NO_FORMATTING
10
11#include "dtfmapts.h"
12
13#include "unicode/datefmt.h"
14#include "unicode/smpdtfmt.h"
15#include "unicode/decimfmt.h"
16#include "unicode/choicfmt.h"
17#include "unicode/msgfmt.h"
18
19
20// This is an API test, not a unit test.  It doesn't test very many cases, and doesn't
21// try to test the full functionality.  It just calls each function in the class and
22// verifies that it works on a basic level.
23
24void IntlTestDateFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
25{
26    if (exec) logln("TestSuite DateFormatAPI");
27    switch (index) {
28        case 0: name = "DateFormat API test";
29                if (exec) {
30                    logln("DateFormat API test---"); logln("");
31                    UErrorCode status = U_ZERO_ERROR;
32                    Locale saveLocale;
33                    Locale::setDefault(Locale::getEnglish(), status);
34                    if(U_FAILURE(status)) {
35                        errln("ERROR: Could not set default locale, test may not give correct results");
36                    }
37                    testAPI(/*par*/);
38                    Locale::setDefault(saveLocale, status);
39                }
40                break;
41
42        case 1: name = "TestEquals";
43                if (exec) {
44                    logln("TestEquals---"); logln("");
45                    TestEquals();
46                }
47                break;
48
49        case 2: name = "TestNameHiding";
50                if (exec) {
51                    logln("TestNameHiding---"); logln("");
52                    TestNameHiding();
53                }
54                break;
55
56        case 3: name = "TestCoverage";
57                if (exec) {
58                    logln("TestCoverage---"); logln("");
59                    TestCoverage();
60                }
61                break;
62
63        default: name = ""; break;
64    }
65}
66
67/**
68 * Add better code coverage.
69 */
70void IntlTestDateFormatAPI::TestCoverage(void)
71{
72    const char *LOCALES[] = {
73            "zh_CN@calendar=chinese",
74            "cop_EG@calendar=coptic",
75            "hi_IN@calendar=indian",
76            "am_ET@calendar=ethiopic"
77    };
78    int32_t numOfLocales = 4;
79
80    for (int32_t i = 0; i < numOfLocales; i++) {
81        DateFormat *df = DateFormat::createDateTimeInstance(DateFormat::kMedium, DateFormat::kMedium, Locale(LOCALES[i]));
82        if (df == NULL){
83            dataerrln("Error creating DateFormat instances.");
84            return;
85        }
86        delete df;
87    }
88}
89/**
90 * Test that the equals method works correctly.
91 */
92void IntlTestDateFormatAPI::TestEquals(void)
93{
94    UErrorCode status = U_ZERO_ERROR;
95    // Create two objects at different system times
96    DateFormat *a = DateFormat::createInstance();
97    UDate start = Calendar::getNow();
98    while (Calendar::getNow() == start) ; // Wait for time to change
99    DateFormat *b = DateFormat::createInstance();
100
101    if (a == NULL || b == NULL){
102        dataerrln("Error calling DateFormat::createInstance()");
103        delete a;
104        delete b;
105        return;
106    }
107
108    if (!(*a == *b))
109        errln("FAIL: DateFormat objects created at different times are unequal.");
110
111    if (b->getDynamicClassID() == SimpleDateFormat::getStaticClassID())
112    {
113        double ONE_YEAR = 365*24*60*60*1000.0;
114        ((SimpleDateFormat*)b)->set2DigitYearStart(start + 50*ONE_YEAR, status);
115        if (U_FAILURE(status))
116            errln("FAIL: setTwoDigitStartDate failed.");
117        else if (*a == *b)
118            errln("FAIL: DateFormat objects with different two digit start dates are equal.");
119    }
120    delete a;
121    delete b;
122}
123
124/**
125 * This test checks various generic API methods in DateFormat to achieve 100%
126 * API coverage.
127 */
128void IntlTestDateFormatAPI::testAPI(/* char* par */)
129{
130    UErrorCode status = U_ZERO_ERROR;
131
132// ======= Test constructors
133
134    logln("Testing DateFormat constructors");
135
136    DateFormat *def = DateFormat::createInstance();
137    DateFormat *fr = DateFormat::createTimeInstance(DateFormat::FULL, Locale::getFrench());
138    DateFormat *it = DateFormat::createDateInstance(DateFormat::MEDIUM, Locale::getItalian());
139    DateFormat *de = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG, Locale::getGerman());
140
141    if (def == NULL || fr == NULL || it == NULL || de == NULL){
142        dataerrln("Error creating DateFormat instances.");
143    }
144
145// ======= Test equality
146if (fr != NULL && def != NULL)
147{
148    logln("Testing equality operator");
149
150    if( *fr == *it ) {
151        errln("ERROR: == failed");
152    }
153}
154
155// ======= Test various format() methods
156if (fr != NULL && it != NULL && de != NULL)
157{
158    logln("Testing various format() methods");
159
160    UDate d = 837039928046.0;
161    Formattable fD(d, Formattable::kIsDate);
162
163    UnicodeString res1, res2, res3;
164    FieldPosition pos1(0), pos2(0);
165
166    status = U_ZERO_ERROR;
167    res1 = fr->format(d, res1, pos1, status);
168    if(U_FAILURE(status)) {
169        errln("ERROR: format() failed (French)");
170    }
171    logln( (UnicodeString) "" + d + " formatted to " + res1);
172
173    res2 = it->format(d, res2, pos2);
174    logln( (UnicodeString) "" + d + " formatted to " + res2);
175
176    res3 = de->format(d, res3);
177    logln( (UnicodeString) "" + d + " formatted to " + res3);
178}
179
180// ======= Test parse()
181if (def != NULL)
182{
183    logln("Testing parse()");
184
185    UnicodeString text("02/03/76 2:50 AM, CST");
186    Formattable result1;
187    UDate result2, result3;
188    ParsePosition pos(0), pos01(0);
189    def->parseObject(text, result1, pos);
190    if(result1.getType() != Formattable::kDate) {
191        errln("ERROR: parseObject() failed for " + text);
192    }
193    logln(text + " parsed into " + result1.getDate());
194
195    status = U_ZERO_ERROR;
196    result2 = def->parse(text, status);
197    if(U_FAILURE(status)) {
198        errln("ERROR: parse() failed, stopping testing");
199        return;
200    }
201    logln(text + " parsed into " + result2);
202
203    result3 = def->parse(text, pos01);
204    logln(text + " parsed into " + result3);
205}
206
207// ======= Test getters and setters
208if (fr != NULL && it != NULL && de != NULL)
209{
210    logln("Testing getters and setters");
211
212    int32_t count = 0;
213    const Locale *locales = DateFormat::getAvailableLocales(count);
214    logln((UnicodeString) "Got " + count + " locales" );
215    for(int32_t i = 0; i < count; i++) {
216        UnicodeString name;
217        name = locales[i].getName();
218        logln(name);
219    }
220
221    fr->setLenient(it->isLenient());
222    if(fr->isLenient() != it->isLenient()) {
223        errln("ERROR: setLenient() failed");
224    }
225
226    const Calendar *cal = def->getCalendar();
227    Calendar *newCal = cal->clone();
228    de->adoptCalendar(newCal);
229    it->setCalendar(*newCal);
230    if( *(de->getCalendar()) != *(it->getCalendar())) {
231        errln("ERROR: adopt or set Calendar() failed");
232    }
233
234    const NumberFormat *nf = def->getNumberFormat();
235    NumberFormat *newNf = (NumberFormat*) nf->clone();
236    de->adoptNumberFormat(newNf);
237    it->setNumberFormat(*newNf);
238    if( *(de->getNumberFormat()) != *(it->getNumberFormat())) {
239        errln("ERROR: adopt or set NumberFormat() failed");
240    }
241
242    const TimeZone& tz = def->getTimeZone();
243    TimeZone *newTz = tz.clone();
244    de->adoptTimeZone(newTz);
245    it->setTimeZone(*newTz);
246    if( de->getTimeZone() != it->getTimeZone()) {
247        errln("ERROR: adopt or set TimeZone() failed");
248    }
249}
250// ======= Test getStaticClassID()
251
252    logln("Testing getStaticClassID()");
253
254    status = U_ZERO_ERROR;
255    DateFormat *test = new SimpleDateFormat(status);
256    if(U_FAILURE(status)) {
257        dataerrln("ERROR: Couldn't create a DateFormat - %s", u_errorName(status));
258    }
259
260    if(test->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
261        errln("ERROR: getDynamicClassID() didn't return the expected value");
262    }
263
264    delete test;
265    delete def;
266    delete fr;
267    delete it;
268    delete de;
269}
270
271/**
272 * Test hiding of parse() and format() APIs in the Format hierarchy.
273 * We test the entire hierarchy, even though this test is located in
274 * the DateFormat API test.
275 */
276void
277IntlTestDateFormatAPI::TestNameHiding(void) {
278
279    // N.B.: This test passes if it COMPILES, since it's a test of
280    // compile-time name hiding.
281
282    UErrorCode status = U_ZERO_ERROR;
283    Formattable dateObj(0, Formattable::kIsDate);
284    Formattable numObj(3.1415926535897932384626433832795);
285    Formattable obj;
286    UnicodeString str;
287    FieldPosition fpos;
288    ParsePosition ppos;
289
290    // DateFormat calling Format API
291    {
292        logln("DateFormat");
293        DateFormat *dateFmt = DateFormat::createInstance();
294        if (dateFmt) {
295            dateFmt->format(dateObj, str, status);
296            dateFmt->format(dateObj, str, fpos, status);
297            delete dateFmt;
298        } else {
299            dataerrln("FAIL: Can't create DateFormat");
300        }
301    }
302
303    // SimpleDateFormat calling Format & DateFormat API
304    {
305        logln("SimpleDateFormat");
306        status = U_ZERO_ERROR;
307        SimpleDateFormat sdf(status);
308        // Format API
309        sdf.format(dateObj, str, status);
310        sdf.format(dateObj, str, fpos, status);
311        // DateFormat API
312        sdf.format((UDate)0, str, fpos);
313        sdf.format((UDate)0, str);
314        sdf.parse(str, status);
315        sdf.parse(str, ppos);
316    }
317
318    // NumberFormat calling Format API
319    {
320        logln("NumberFormat");
321        status = U_ZERO_ERROR;
322        NumberFormat *fmt = NumberFormat::createInstance(status);
323        if (fmt) {
324            fmt->format(numObj, str, status);
325            fmt->format(numObj, str, fpos, status);
326            delete fmt;
327        } else {
328            dataerrln("FAIL: Can't create NumberFormat()");
329        }
330    }
331
332    // DecimalFormat calling Format & NumberFormat API
333    {
334        logln("DecimalFormat");
335        status = U_ZERO_ERROR;
336        DecimalFormat fmt(status);
337        if(U_SUCCESS(status)) {
338          // Format API
339          fmt.format(numObj, str, status);
340          fmt.format(numObj, str, fpos, status);
341          // NumberFormat API
342          fmt.format(2.71828, str);
343          fmt.format((int32_t)1234567, str);
344          fmt.format(1.41421, str, fpos);
345          fmt.format((int32_t)9876543, str, fpos);
346          fmt.parse(str, obj, ppos);
347          fmt.parse(str, obj, status);
348        } else {
349          errcheckln(status, "FAIL: Couldn't instantiate DecimalFormat, error %s. Quitting test", u_errorName(status));
350        }
351    }
352
353    // ChoiceFormat calling Format & NumberFormat API
354    {
355        logln("ChoiceFormat");
356        status = U_ZERO_ERROR;
357        ChoiceFormat fmt("0#foo|1#foos|2#foos", status);
358        // Format API
359        fmt.format(numObj, str, status);
360        fmt.format(numObj, str, fpos, status);
361        // NumberFormat API
362        fmt.format(2.71828, str);
363        fmt.format((int32_t)1234567, str);
364        fmt.format(1.41421, str, fpos);
365        fmt.format((int32_t)9876543, str, fpos);
366        fmt.parse(str, obj, ppos);
367        fmt.parse(str, obj, status);
368    }
369
370    // MessageFormat calling Format API
371    {
372        logln("MessageFormat");
373        status = U_ZERO_ERROR;
374        MessageFormat fmt("", status);
375        // Format API
376        // We use dateObj, which MessageFormat should reject.
377        // We're testing name hiding, not the format method.
378        fmt.format(dateObj, str, status);
379        fmt.format(dateObj, str, fpos, status);
380    }
381}
382
383#endif /* #if !UCONFIG_NO_FORMATTING */
384