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