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