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