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