Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / intltest / tsdate.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /***********************************************************************
4  * Copyright (c) 1997-2009, International Business Machines Corporation
5  * and others. All Rights Reserved.
6  ***********************************************************************/
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_FORMATTING
11
12 #include "unicode/datefmt.h"
13 #include "unicode/smpdtfmt.h"
14 #include "tsdate.h"
15 #include "putilimp.h"
16
17 #include <float.h>
18 #include <stdlib.h>
19 #include <math.h>
20
21 const double IntlTestDateFormat::ONEYEAR = 365.25 * ONEDAY; // Approximate
22
23 IntlTestDateFormat::~IntlTestDateFormat() {}
24
25 /**
26  * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
27  * DateFormat.
28  */
29 // par is ignored throughout this file
30 void IntlTestDateFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
31 {
32     if (exec) logln("TestSuite DateFormat");
33     switch (index) {
34         case 0: name = "GenericTest";
35             if (exec) {
36                 logln(name);
37                 fFormat = DateFormat::createInstance();
38                 fTestName = "createInstance";
39                 fLimit = 3;
40                 testFormat(/* par */);
41             }
42             break;
43         case 1: name = "DefaultLocale";
44             if (exec) {
45                 logln(name);
46                 testLocale(/*par, */Locale::getDefault(), "Default Locale");
47             }
48             break;
49
50         case 2: name = "TestAvailableLocales";
51             if (exec) {
52                 logln(name);
53                 testAvailableLocales(/* par */);
54             }
55             break;
56
57         case 3: name = "MonsterTest";
58             if (exec) {
59                 logln(name);
60                 monsterTest(/*par*/);
61             }
62             break;
63
64         default: name = ""; break;
65     }
66 }
67
68 void
69 IntlTestDateFormat::testLocale(/*char* par, */const Locale& locale, const UnicodeString& localeName)
70 {
71     DateFormat::EStyle timeStyle, dateStyle;
72     
73     // For patterns including only time information and a timezone, it may take
74     // up to three iterations, since the timezone may shift as the year number
75     // is determined.  For other patterns, 2 iterations should suffice.
76     fLimit = 3;
77
78     for(timeStyle = (DateFormat::EStyle)0; 
79         timeStyle < (DateFormat::EStyle)4; 
80         timeStyle = (DateFormat::EStyle) (timeStyle+1))
81     {
82         fTestName = (UnicodeString) "Time test " + (int32_t) timeStyle + " (" + localeName + ")";
83         fFormat = DateFormat::createTimeInstance(timeStyle, locale);
84         testFormat(/* par */);
85     }
86
87     fLimit = 2;
88
89     for(dateStyle = (DateFormat::EStyle)0; 
90         dateStyle < (DateFormat::EStyle)4; 
91         dateStyle = (DateFormat::EStyle) (dateStyle+1))
92     {
93         fTestName = (UnicodeString) "Date test " + (int32_t) dateStyle + " (" + localeName + ")";
94         fFormat = DateFormat::createDateInstance(dateStyle, locale);
95         testFormat(/* par */);
96     }
97
98     for(dateStyle = (DateFormat::EStyle)0; 
99         dateStyle < (DateFormat::EStyle)4; 
100         dateStyle = (DateFormat::EStyle) (dateStyle+1))
101     {
102         for(timeStyle = (DateFormat::EStyle)0; 
103             timeStyle < (DateFormat::EStyle)4; 
104             timeStyle = (DateFormat::EStyle) (timeStyle+1))
105         {
106             fTestName = (UnicodeString) "DateTime test " + (int32_t) dateStyle + "/" + (int32_t) timeStyle + " (" + localeName + ")";
107             fFormat = DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale);
108             testFormat(/* par */);
109         }
110     }
111 }
112
113 void IntlTestDateFormat::testFormat(/* char* par */)
114 {
115     if (fFormat == 0)
116     {
117         dataerrln("FAIL: DateFormat creation failed");
118         return;
119     }
120
121     describeTest();
122
123     UDate now = Calendar::getNow();
124     tryDate(0);
125     tryDate(1278161801778.0);
126     tryDate(5264498352317.0);   // Sunday, October 28, 2136 8:39:12 AM PST
127     tryDate(9516987689250.0);   // In the year 2271
128     tryDate(now);
129     // Shift 6 months into the future, AT THE SAME TIME OF DAY.
130     // This will test the DST handling.
131     tryDate(now + 6.0*30*ONEDAY);
132
133     UDate limit = now * 10; // Arbitrary limit
134     for (int32_t i=0; i<3; ++i)
135         tryDate(uprv_floor(randDouble() * limit));
136
137     delete fFormat;
138 }
139
140 void
141 IntlTestDateFormat::describeTest()
142 {
143     // Assume it's a SimpleDateFormat and get some info
144     SimpleDateFormat *s = (SimpleDateFormat*)fFormat;
145     UnicodeString str;
146     logln(fTestName + " Pattern " + s->toPattern(str));
147 }
148
149 void IntlTestDateFormat::tryDate(UDate theDate)
150 {
151     const int32_t DEPTH = 10;
152     UDate date[DEPTH];
153     UnicodeString string[DEPTH];
154
155     int32_t dateMatch = 0;
156     int32_t stringMatch = 0;
157     UBool dump = FALSE;
158 #if defined (U_CAL_DEBUG)
159     dump = TRUE;
160 #endif
161     int32_t i;
162
163     date[0] = theDate;
164     fFormat->format(theDate, string[0]);
165
166     for (i=1; i<DEPTH; ++i)
167     {
168         UErrorCode status = U_ZERO_ERROR;
169         date[i] = fFormat->parse(string[i-1], status);
170         if (U_FAILURE(status))
171         {
172             describeTest();
173             errln("**** FAIL: Parse of " + prettify(string[i-1], FALSE) + " failed.");
174             dump = TRUE;
175             break;
176         }
177         fFormat->format(date[i], string[i]);
178         if (dateMatch == 0 && date[i] == date[i-1])
179             dateMatch = i;
180         else if (dateMatch > 0 && date[i] != date[i-1])
181         {
182             describeTest();
183             errln("**** FAIL: Date mismatch after match for " + string[i]);
184             dump = TRUE;
185             break;
186         }
187         if (stringMatch == 0 && string[i] == string[i-1])
188             stringMatch = i;
189         else if (stringMatch > 0 && string[i] != string[i-1])
190         {
191             describeTest();
192             errln("**** FAIL: String mismatch after match for " + string[i]);
193             dump = TRUE;
194             break;
195         }
196         if (dateMatch > 0 && stringMatch > 0)
197             break;
198     }
199     if (i == DEPTH)
200         --i;
201
202     if (stringMatch > fLimit || dateMatch > fLimit)
203     {
204         describeTest();
205         errln((UnicodeString)"**** FAIL: No string and/or date match within " + fLimit
206             + " iterations for the Date " + string[0] + "\t(" + theDate + ").");
207         dump = TRUE;
208     }
209
210     if (dump)
211     {
212         for (int32_t k=0; k<=i; ++k)
213         {
214             logln((UnicodeString)"" + k + ": " + date[k] + " F> " +
215                   string[k] + " P> ");
216         }
217     }
218 }
219
220 // Return a random double from 0.01 to 1, inclusive
221 double IntlTestDateFormat::randDouble()
222 {
223     // Assume 8-bit (or larger) rand values.  Also assume
224     // that the system rand() function is very poor, which it always is.
225     double d=0.0;
226     uint32_t i;
227     char* poke = (char*)&d;
228     do {
229         do {
230             for (i=0; i < sizeof(double); ++i)
231             {
232                 poke[i] = (char)(rand() & 0xFF);
233             }
234         } while (uprv_isNaN(d) || uprv_isInfinite(d));
235
236         if (d < 0.0)
237             d = -d;
238         if (d > 0.0)
239         {
240             double e = uprv_floor(log10(d));
241             if (e < -2.0)
242                 d *= uprv_pow10((int32_t)(-e-2));
243             else if (e > -1.0)
244                 d /= uprv_pow10((int32_t)(e+1));
245         }
246     // While this is not a real normalized number make another one.
247     } while (uprv_isNaN(d) || uprv_isInfinite(d)
248         || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
249     return d;
250 }
251
252 void IntlTestDateFormat::testAvailableLocales(/* char* par */)
253 {
254     int32_t count = 0;
255     const Locale* locales = DateFormat::getAvailableLocales(count);
256     logln((UnicodeString)"" + count + " available locales");
257     if (locales && count)
258     {
259         UnicodeString name;
260         UnicodeString all;
261         for (int32_t i=0; i<count; ++i)
262         {
263             if (i!=0) all += ", ";
264             all += locales[i].getName();
265         }
266         logln(all);
267     }
268     else dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
269 }
270
271 void IntlTestDateFormat::monsterTest(/*char *par*/)
272 {
273     int32_t count;
274     const Locale* locales = DateFormat::getAvailableLocales(count);
275     if (locales && count)
276     {
277         if (quick && count > 3) {
278             logln("quick test: testing just 3 locales!");
279             count = 3;
280         }
281         for (int32_t i=0; i<count; ++i)
282         {
283             UnicodeString name = UnicodeString(locales[i].getName(), "");
284             logln((UnicodeString)"Testing " + name + "...");
285             testLocale(/*par, */locales[i], name);
286         }
287     }
288 }
289
290 #endif /* #if !UCONFIG_NO_FORMATTING */