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