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