]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
374ca955 | 3 | /*********************************************************************** |
729e4ab9 | 4 | * Copyright (c) 1997-2009, International Business Machines Corporation |
374ca955 A |
5 | * and others. All Rights Reserved. |
6 | ***********************************************************************/ | |
b75a7d8f A |
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" | |
374ca955 | 15 | #include "putilimp.h" |
b75a7d8f A |
16 | |
17 | #include <float.h> | |
18 | #include <stdlib.h> | |
73c04bcf | 19 | #include <math.h> |
b75a7d8f A |
20 | |
21 | const double IntlTestDateFormat::ONEYEAR = 365.25 * ONEDAY; // Approximate | |
22 | ||
374ca955 A |
23 | IntlTestDateFormat::~IntlTestDateFormat() {} |
24 | ||
b75a7d8f A |
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 | { | |
729e4ab9 | 117 | dataerrln("FAIL: DateFormat creation failed"); |
b75a7d8f A |
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; | |
374ca955 A |
158 | #if defined (U_CAL_DEBUG) |
159 | dump = TRUE; | |
160 | #endif | |
b75a7d8f A |
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 | } | |
73c04bcf | 219 | |
b75a7d8f A |
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 | { | |
73c04bcf | 240 | double e = uprv_floor(log10(d)); |
b75a7d8f A |
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 | } | |
729e4ab9 | 268 | else dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer"); |
b75a7d8f A |
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 */ |