]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tsnmfmt.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / test / intltest / tsnmfmt.cpp
1 /***********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2009, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ***********************************************************************/
6
7 #include "unicode/utypes.h"
8
9 #if !UCONFIG_NO_FORMATTING
10
11 #include "unicode/decimfmt.h"
12 #include "tsnmfmt.h"
13 #include "putilimp.h"
14 #include <float.h>
15 #include <stdlib.h>
16
17 IntlTestNumberFormat::~IntlTestNumberFormat() {}
18
19 static const char * formattableTypeName(Formattable::Type t)
20 {
21 switch(t) {
22 case Formattable::kDate: return "kDate";
23 case Formattable::kDouble: return "kDouble";
24 case Formattable::kLong: return "kLong";
25 case Formattable::kString: return "kString";
26 case Formattable::kArray: return "kArray";
27 case Formattable::kInt64: return "kInt64";
28 default: return "??unknown??";
29 }
30 }
31
32 /**
33 * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
34 * NumberFormat.
35 */
36 void IntlTestNumberFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
37 {
38
39 if (exec) logln((UnicodeString)"TestSuite NumberFormat");
40 switch (index) {
41 case 0: name = "createInstance";
42 if (exec)
43 {
44 logln(name);
45 fStatus = U_ZERO_ERROR;
46 fFormat = NumberFormat::createInstance(fStatus);
47 testFormat(/*par*/);
48 }
49 break;
50
51 case 1: name = "DefaultLocale";
52 if (exec) testLocale(/*par, */Locale::getDefault(), name);
53 break;
54
55 case 2: name = "testAvailableLocales";
56 if (exec) {
57 logln(name);
58 testAvailableLocales(/*par*/);
59 }
60 break;
61
62 case 3: name = "monsterTest";
63 if (exec) {
64 logln(name);
65 monsterTest(/*par*/);
66 }
67 break;
68
69 default: name = ""; break;
70 }
71 }
72
73 void
74 IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const UnicodeString& localeName)
75 {
76 const char* name;
77
78 fLocale = locale;
79 name = "Number test";
80 logln((UnicodeString)name + " (" + localeName + ")");
81 fStatus = U_ZERO_ERROR;
82 fFormat = NumberFormat::createInstance(locale, fStatus);
83 testFormat(/* par */);
84
85 name = "Currency test";
86 logln((UnicodeString)name + " (" + localeName + ")");
87 fStatus = U_ZERO_ERROR;
88 fFormat = NumberFormat::createCurrencyInstance(locale, fStatus);
89 testFormat(/* par */);
90
91 name = "Percent test";
92 logln((UnicodeString)name + " (" + localeName + ")");
93 fStatus = U_ZERO_ERROR;
94 fFormat = NumberFormat::createPercentInstance(locale, fStatus);
95 testFormat(/* par */);
96
97 name = "Scientific test";
98 logln((UnicodeString)name + " (" + localeName + ")");
99 fStatus = U_ZERO_ERROR;
100 fFormat = NumberFormat::createScientificInstance(locale, fStatus);
101 testFormat(/* par */);
102 }
103
104 double IntlTestNumberFormat::randDouble()
105 {
106 // Assume 8-bit (or larger) rand values. Also assume
107 // that the system rand() function is very poor, which it always is.
108 // Call srand(currentTime) in intltest to make it truly random.
109 double d;
110 uint32_t i;
111 char* poke = (char*)&d;
112 do {
113 for (i=0; i < sizeof(double); ++i)
114 {
115 poke[i] = (char)(rand() & 0xFF);
116 }
117 } while (uprv_isNaN(d) || uprv_isInfinite(d)
118 || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
119
120 return d;
121 }
122
123 /*
124 * Return a random uint32_t
125 **/
126 uint32_t IntlTestNumberFormat::randLong()
127 {
128 // Assume 8-bit (or larger) rand values. Also assume
129 // that the system rand() function is very poor, which it always is.
130 // Call srand(currentTime) in intltest to make it truly random.
131 uint32_t d;
132 uint32_t i;
133 char* poke = (char*)&d;
134 for (i=0; i < sizeof(uint32_t); ++i)
135 {
136 poke[i] = (char)(rand() & 0xFF);
137 }
138 return d;
139 }
140
141
142 /* Make sure that we don't get something too large and multiply into infinity.
143 @param smallerThanMax the requested maximum value smaller than DBL_MAX */
144 double IntlTestNumberFormat::getSafeDouble(double smallerThanMax) {
145 double it;
146 double high = (DBL_MAX/smallerThanMax)/10.0;
147 double low = -high;
148 do {
149 it = randDouble();
150 } while (low > it || it > high);
151 return it;
152 }
153
154 void
155 IntlTestNumberFormat::testFormat(/* char* par */)
156 {
157 if (U_FAILURE(fStatus))
158 {
159 dataerrln((UnicodeString)"**** FAIL: createXxxInstance failed. - " + u_errorName(fStatus));
160 if (fFormat != 0)
161 errln("**** FAIL: Non-null format returned by createXxxInstance upon failure.");
162 delete fFormat;
163 fFormat = 0;
164 return;
165 }
166
167 if (fFormat == 0)
168 {
169 errln((UnicodeString)"**** FAIL: Null format returned by createXxxInstance.");
170 return;
171 }
172
173 UnicodeString str;
174
175 // Assume it's a DecimalFormat and get some info
176 DecimalFormat *s = (DecimalFormat*)fFormat;
177 logln((UnicodeString)" Pattern " + s->toPattern(str));
178
179 #if defined(OS390) || defined(OS400)
180 tryIt(-2.02147304840132e-68);
181 tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac
182 tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent
183 tryIt(9.29526819488338e+64); // Ok -- used to fail?
184 #else
185 tryIt(-2.02147304840132e-100);
186 tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac
187 tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent
188 tryIt(9.29526819488338e+250); // Ok -- used to fail?
189 #endif
190
191 // These PASS now, with the sprintf/atof based format-parse.
192
193 // These fail due to round-off
194 // The least significant digit drops by one during each format-parse cycle.
195 // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %)
196 #ifdef OS390
197 tryIt(-9.18228054496402e+64);
198 tryIt(-9.69413034454191e+64);
199 #else
200 tryIt(-9.18228054496402e+255);
201 tryIt(-9.69413034454191e+273);
202 #endif
203
204 #ifndef OS390
205 tryIt(1.234e-200);
206 tryIt(-2.3e-168);
207
208 tryIt(uprv_getNaN());
209 tryIt(uprv_getInfinity());
210 tryIt(-uprv_getInfinity());
211 #endif
212
213 tryIt((int32_t)251887531);
214 tryIt(5e-20 / 9);
215 tryIt(5e20 / 9);
216 tryIt(1.234e-50);
217 tryIt(9.99999999999996);
218 tryIt(9.999999999999996);
219
220 tryIt(5.06e-27);
221
222 tryIt((int32_t)INT32_MIN);
223 tryIt((int32_t)INT32_MAX);
224 tryIt((double)INT32_MIN);
225 tryIt((double)INT32_MAX);
226 tryIt((double)INT32_MIN - 1.0);
227 tryIt((double)INT32_MAX + 1.0);
228
229 tryIt(5.0 / 9.0 * 1e-20);
230 tryIt(4.0 / 9.0 * 1e-20);
231 tryIt(5.0 / 9.0 * 1e+20);
232 tryIt(4.0 / 9.0 * 1e+20);
233
234 tryIt(2147483647.);
235 tryIt((int32_t)0);
236 tryIt(0.0);
237 tryIt((int32_t)1);
238 tryIt((int32_t)10);
239 tryIt((int32_t)100);
240 tryIt((int32_t)-1);
241 tryIt((int32_t)-10);
242 tryIt((int32_t)-100);
243 tryIt((int32_t)-1913860352);
244
245 for (int32_t z=0; z<10; ++z)
246 {
247 double d = randFraction() * 2e10 - 1e10;
248 tryIt(d);
249 }
250
251 double it = getSafeDouble(100000.0);
252
253 tryIt(0.0);
254 tryIt(it);
255 tryIt((int32_t)0);
256 tryIt(uprv_floor(it));
257 tryIt((int32_t)randLong());
258
259 // try again
260 it = getSafeDouble(100.0);
261 tryIt(it);
262 tryIt(uprv_floor(it));
263 tryIt((int32_t)randLong());
264
265 // try again with very large numbers
266 it = getSafeDouble(100000000000.0);
267 tryIt(it);
268
269 // try again with very large numbers
270 // and without going outside of the int32_t range
271 it = randFraction() * INT32_MAX;
272 tryIt(it);
273 tryIt((int32_t)uprv_floor(it));
274
275 delete fFormat;
276 }
277
278 void
279 IntlTestNumberFormat::tryIt(double aNumber)
280 {
281 const int32_t DEPTH = 10;
282 Formattable number[DEPTH];
283 UnicodeString string[DEPTH];
284
285 int32_t numberMatch = 0;
286 int32_t stringMatch = 0;
287 UnicodeString errMsg;
288 int32_t i;
289 for (i=0; i<DEPTH; ++i)
290 {
291 errMsg.truncate(0); // if non-empty, we failed this iteration
292 UErrorCode status = U_ZERO_ERROR;
293 string[i] = "(n/a)"; // "format was never done" value
294 if (i == 0) {
295 number[i].setDouble(aNumber);
296 } else {
297 fFormat->parse(string[i-1], number[i], status);
298 if (U_FAILURE(status)) {
299 number[i].setDouble(1234.5); // "parse failed" value
300 errMsg = "**** FAIL: Parse of " + prettify(string[i-1]) + " failed.";
301 --i; // don't show empty last line: "1234.5 F> (n/a) P>"
302 break;
303 }
304 }
305 // Convert from long to double
306 if (number[i].getType() == Formattable::kLong)
307 number[i].setDouble(number[i].getLong());
308 else if (number[i].getType() == Formattable::kInt64)
309 number[i].setDouble((double)number[i].getInt64());
310 else if (number[i].getType() != Formattable::kDouble)
311 {
312 errMsg = ("**** FAIL: Parse of " + prettify(string[i-1])
313 + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number[i].getType()))
314 + ", Locale=" + UnicodeString(fLocale.getName())
315 + ", longValue=" + number[i].getLong());
316 break;
317 }
318 string[i].truncate(0);
319 fFormat->format(number[i].getDouble(), string[i]);
320 if (i > 0)
321 {
322 if (numberMatch == 0 && number[i] == number[i-1])
323 numberMatch = i;
324 else if (numberMatch > 0 && number[i] != number[i-1])
325 {
326 errMsg = ("**** FAIL: Numeric mismatch after match.");
327 break;
328 }
329 if (stringMatch == 0 && string[i] == string[i-1])
330 stringMatch = i;
331 else if (stringMatch > 0 && string[i] != string[i-1])
332 {
333 errMsg = ("**** FAIL: String mismatch after match.");
334 break;
335 }
336 }
337 if (numberMatch > 0 && stringMatch > 0)
338 break;
339 }
340 if (i == DEPTH)
341 --i;
342
343 if (stringMatch > 2 || numberMatch > 2)
344 {
345 errMsg = ("**** FAIL: No string and/or number match within 2 iterations.");
346 }
347
348 if (errMsg.length() != 0)
349 {
350 for (int32_t k=0; k<=i; ++k)
351 {
352 logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " +
353 prettify(string[k]) + " P> ");
354 }
355 errln(errMsg);
356 }
357 }
358
359 void
360 IntlTestNumberFormat::tryIt(int32_t aNumber)
361 {
362 Formattable number(aNumber);
363 UnicodeString stringNum;
364 UErrorCode status = U_ZERO_ERROR;
365
366 fFormat->format(number, stringNum, status);
367 if (U_FAILURE(status))
368 {
369 errln("**** FAIL: Formatting " + aNumber);
370 return;
371 }
372 fFormat->parse(stringNum, number, status);
373 if (U_FAILURE(status))
374 {
375 errln("**** FAIL: Parse of " + prettify(stringNum) + " failed.");
376 return;
377 }
378 if (number.getType() != Formattable::kLong)
379 {
380 errln("**** FAIL: Parse of " + prettify(stringNum)
381 + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number.getType()))
382 + ", Locale=" + UnicodeString(fLocale.getName())
383 + ", doubleValue=" + number.getDouble()
384 + ", longValue=" + number.getLong()
385 + ", origValue=" + aNumber
386 );
387 }
388 if (number.getLong() != aNumber) {
389 errln("**** FAIL: Parse of " + prettify(stringNum) + " failed. Got:" + number.getLong()
390 + " Expected:" + aNumber);
391 }
392 }
393
394 void IntlTestNumberFormat::testAvailableLocales(/* char* par */)
395 {
396 int32_t count = 0;
397 const Locale* locales = NumberFormat::getAvailableLocales(count);
398 logln((UnicodeString)"" + count + " available locales");
399 if (locales && count)
400 {
401 UnicodeString name;
402 UnicodeString all;
403 for (int32_t i=0; i<count; ++i)
404 {
405 if (i!=0)
406 all += ", ";
407 all += locales[i].getName();
408 }
409 logln(all);
410 }
411 else
412 dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
413 }
414
415 void IntlTestNumberFormat::monsterTest(/* char* par */)
416 {
417 const char *SEP = "============================================================\n";
418 int32_t count;
419 const Locale* allLocales = NumberFormat::getAvailableLocales(count);
420 Locale* locales = (Locale*)allLocales;
421 Locale quickLocales[6];
422 if (allLocales && count)
423 {
424 if (quick && count > 6) {
425 logln("quick test: testing just 6 locales!");
426 count = 6;
427 locales = quickLocales;
428 locales[0] = allLocales[0];
429 locales[1] = allLocales[1];
430 locales[2] = allLocales[2];
431 // In a quick test, make sure we test locales that use
432 // currency prefix, currency suffix, and choice currency
433 // logic. Otherwise bugs in these areas can slip through.
434 locales[3] = Locale("ar", "AE", "");
435 locales[4] = Locale("cs", "CZ", "");
436 locales[5] = Locale("en", "IN", "");
437 }
438 for (int32_t i=0; i<count; ++i)
439 {
440 UnicodeString name(locales[i].getName(), "");
441 logln(SEP);
442 testLocale(/* par, */locales[i], name);
443 }
444 }
445
446 logln(SEP);
447 }
448
449 #endif /* #if !UCONFIG_NO_FORMATTING */