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