1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /***********************************************************************
5 * Copyright (c) 1997-2012, International Business Machines Corporation
6 * and others. All Rights Reserved.
7 ***********************************************************************/
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/decimfmt.h"
20 IntlTestNumberFormat::~IntlTestNumberFormat() {}
22 static const char * formattableTypeName(Formattable::Type t)
25 case Formattable::kDate: return "kDate";
26 case Formattable::kDouble: return "kDouble";
27 case Formattable::kLong: return "kLong";
28 case Formattable::kString: return "kString";
29 case Formattable::kArray: return "kArray";
30 case Formattable::kInt64: return "kInt64";
31 default: return "??unknown??";
36 * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
39 void IntlTestNumberFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
42 if (exec) logln((UnicodeString)"TestSuite NumberFormat");
44 case 0: name = "createInstance";
48 fStatus = U_ZERO_ERROR;
49 fFormat = NumberFormat::createInstance(fStatus);
54 case 1: name = "DefaultLocale";
55 if (exec) testLocale(/*par, */Locale::getDefault(), name);
58 case 2: name = "testAvailableLocales";
61 testAvailableLocales(/*par*/);
65 case 3: name = "monsterTest";
72 default: name = ""; break;
77 IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const UnicodeString& localeName)
83 logln((UnicodeString)name + " (" + localeName + ")");
84 fStatus = U_ZERO_ERROR;
85 fFormat = NumberFormat::createInstance(locale, fStatus);
86 testFormat(/* par */);
88 name = "Currency test";
89 logln((UnicodeString)name + " (" + localeName + ")");
90 fStatus = U_ZERO_ERROR;
91 fFormat = NumberFormat::createCurrencyInstance(locale, fStatus);
92 testFormat(/* par */);
94 name = "Percent test";
95 logln((UnicodeString)name + " (" + localeName + ")");
96 fStatus = U_ZERO_ERROR;
97 fFormat = NumberFormat::createPercentInstance(locale, fStatus);
98 testFormat(/* par */);
100 if (uprv_strcmp(locale.getName(), "en_US_POSIX") != 0) {
101 name = "Scientific test";
102 logln((UnicodeString)name + " (" + localeName + ")");
103 fStatus = U_ZERO_ERROR;
104 fFormat = NumberFormat::createScientificInstance(locale, fStatus);
105 testFormat(/* par */);
109 double IntlTestNumberFormat::randDouble()
111 // Assume 8-bit (or larger) rand values. Also assume
112 // that the system rand() function is very poor, which it always is.
113 // Call srand(currentTime) in intltest to make it truly random.
116 char* poke = (char*)&d;
118 for (i=0; i < sizeof(double); ++i)
120 poke[i] = (char)(rand() & 0xFF);
122 } while (uprv_isNaN(d) || uprv_isInfinite(d)
123 || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
129 * Return a random uint32_t
131 uint32_t IntlTestNumberFormat::randLong()
133 // Assume 8-bit (or larger) rand values. Also assume
134 // that the system rand() function is very poor, which it always is.
135 // Call srand(currentTime) in intltest to make it truly random.
138 char* poke = (char*)&d;
139 for (i=0; i < sizeof(uint32_t); ++i)
141 poke[i] = (char)(rand() & 0xFF);
147 /* Make sure that we don't get something too large and multiply into infinity.
148 @param smallerThanMax the requested maximum value smaller than DBL_MAX */
149 double IntlTestNumberFormat::getSafeDouble(double smallerThanMax) {
151 double high = (DBL_MAX/smallerThanMax)/10.0;
155 } while (low > it || it > high);
160 IntlTestNumberFormat::testFormat(/* char* par */)
162 if (U_FAILURE(fStatus))
164 dataerrln((UnicodeString)"**** FAIL: createXxxInstance failed. - " + u_errorName(fStatus));
166 errln("**** FAIL: Non-null format returned by createXxxInstance upon failure.");
174 errln((UnicodeString)"**** FAIL: Null format returned by createXxxInstance.");
180 // Assume it's a DecimalFormat and get some info
181 DecimalFormat *s = (DecimalFormat*)fFormat;
182 logln((UnicodeString)" Pattern " + s->toPattern(str));
184 #if U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400
185 tryIt(-2.02147304840132e-68);
186 tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac
187 tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent
188 tryIt(9.29526819488338e+64); // Ok -- used to fail?
190 tryIt(-2.02147304840132e-100);
191 tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac
192 tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent
193 tryIt(9.29526819488338e+250); // Ok -- used to fail?
196 // These PASS now, with the sprintf/atof based format-parse.
198 // These fail due to round-off
199 // The least significant digit drops by one during each format-parse cycle.
200 // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %)
201 #if U_PLATFORM == U_PF_OS390
202 tryIt(-9.18228054496402e+64);
203 tryIt(-9.69413034454191e+64);
205 tryIt(-9.18228054496402e+255);
206 tryIt(-9.69413034454191e+273);
209 #if U_PLATFORM != U_PF_OS390
213 tryIt(uprv_getNaN());
214 tryIt(uprv_getInfinity());
215 tryIt(-uprv_getInfinity());
218 tryIt((int32_t)251887531);
222 tryIt(9.99999999999996);
223 tryIt(9.999999999999996);
227 tryIt((int32_t)INT32_MIN);
228 tryIt((int32_t)INT32_MAX);
229 tryIt((double)INT32_MIN);
230 tryIt((double)INT32_MAX);
231 tryIt((double)INT32_MIN - 1.0);
232 tryIt((double)INT32_MAX + 1.0);
234 tryIt(5.0 / 9.0 * 1e-20);
235 tryIt(4.0 / 9.0 * 1e-20);
236 tryIt(5.0 / 9.0 * 1e+20);
237 tryIt(4.0 / 9.0 * 1e+20);
247 tryIt((int32_t)-100);
248 tryIt((int32_t)-1913860352);
250 for (int32_t z=0; z<10; ++z)
252 double d = randFraction() * 2e10 - 1e10;
256 double it = getSafeDouble(100000.0);
261 tryIt(uprv_floor(it));
262 tryIt((int32_t)randLong());
265 it = getSafeDouble(100.0);
267 tryIt(uprv_floor(it));
268 tryIt((int32_t)randLong());
270 // try again with very large numbers
271 it = getSafeDouble(100000000000.0);
274 // try again with very large numbers
275 // and without going outside of the int32_t range
276 it = randFraction() * INT32_MAX;
278 tryIt((int32_t)uprv_floor(it));
284 IntlTestNumberFormat::tryIt(double aNumber)
286 const int32_t DEPTH = 10;
287 Formattable number[DEPTH];
288 UnicodeString string[DEPTH];
290 int32_t numberMatch = 0;
291 int32_t stringMatch = 0;
292 UnicodeString errMsg;
294 for (i=0; i<DEPTH; ++i)
296 errMsg.truncate(0); // if non-empty, we failed this iteration
297 UErrorCode status = U_ZERO_ERROR;
298 string[i] = "(n/a)"; // "format was never done" value
300 number[i].setDouble(aNumber);
302 fFormat->parse(string[i-1], number[i], status);
303 if (U_FAILURE(status)) {
304 number[i].setDouble(1234.5); // "parse failed" value
305 errMsg = "**** FAIL: Parse of " + prettify(string[i-1]) + " failed.";
306 --i; // don't show empty last line: "1234.5 F> (n/a) P>"
310 // Convert from long to double
311 if (number[i].getType() == Formattable::kLong)
312 number[i].setDouble(number[i].getLong());
313 else if (number[i].getType() == Formattable::kInt64)
314 number[i].setDouble((double)number[i].getInt64());
315 else if (number[i].getType() != Formattable::kDouble)
317 errMsg = ("**** FAIL: Parse of " + prettify(string[i-1])
318 + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number[i].getType()))
319 + ", Locale=" + UnicodeString(fLocale.getName())
320 + ", longValue=" + number[i].getLong());
323 string[i].truncate(0);
324 fFormat->format(number[i].getDouble(), string[i]);
327 if (numberMatch == 0 && number[i] == number[i-1])
329 else if (numberMatch > 0 && number[i] != number[i-1])
331 errMsg = ("**** FAIL: Numeric mismatch after match.");
334 if (stringMatch == 0 && string[i] == string[i-1])
336 else if (stringMatch > 0 && string[i] != string[i-1])
338 errMsg = ("**** FAIL: String mismatch after match.");
342 if (numberMatch > 0 && stringMatch > 0)
348 if (stringMatch > 2 || numberMatch > 2)
350 errMsg = ("**** FAIL: No string and/or number match within 2 iterations.");
353 if (errMsg.length() != 0)
355 for (int32_t k=0; k<=i; ++k)
357 logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " +
358 prettify(string[k]) + " P> ");
365 IntlTestNumberFormat::tryIt(int32_t aNumber)
367 Formattable number(aNumber);
368 UnicodeString stringNum;
369 UErrorCode status = U_ZERO_ERROR;
371 fFormat->format(number, stringNum, status);
372 if (U_FAILURE(status))
374 errln(UnicodeString("**** FAIL: Formatting ") + aNumber);
377 fFormat->parse(stringNum, number, status);
378 if (U_FAILURE(status))
380 errln("**** FAIL: Parse of " + prettify(stringNum) + " failed.");
383 if (number.getType() != Formattable::kLong)
385 errln("**** FAIL: Parse of " + prettify(stringNum)
386 + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number.getType()))
387 + ", Locale=" + UnicodeString(fLocale.getName())
388 + ", doubleValue=" + number.getDouble()
389 + ", longValue=" + number.getLong()
390 + ", origValue=" + aNumber
393 if (number.getLong() != aNumber) {
394 errln("**** FAIL: Parse of " + prettify(stringNum) + " failed. Got:" + number.getLong()
395 + " Expected:" + aNumber);
399 void IntlTestNumberFormat::testAvailableLocales(/* char* par */)
402 const Locale* locales = NumberFormat::getAvailableLocales(count);
403 logln((UnicodeString)"" + count + " available locales");
404 if (locales && count)
408 for (int32_t i=0; i<count; ++i)
412 all += locales[i].getName();
417 dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
420 void IntlTestNumberFormat::monsterTest(/* char* par */)
422 const char *SEP = "============================================================\n";
424 const Locale* allLocales = NumberFormat::getAvailableLocales(count);
425 Locale* locales = (Locale*)allLocales;
426 Locale quickLocales[6];
427 if (allLocales && count)
429 if (quick && count > 6) {
430 logln("quick test: testing just 6 locales!");
432 locales = quickLocales;
433 locales[0] = allLocales[0];
434 locales[1] = allLocales[1];
435 locales[2] = allLocales[2];
436 // In a quick test, make sure we test locales that use
437 // currency prefix, currency suffix, and choice currency
438 // logic. Otherwise bugs in these areas can slip through.
439 locales[3] = Locale("ar", "AE", "");
440 locales[4] = Locale("cs", "CZ", "");
441 locales[5] = Locale("en", "IN", "");
443 for (int32_t i=0; i<count; ++i)
445 UnicodeString name(locales[i].getName(), "");
447 testLocale(/* par, */locales[i], name);
454 #endif /* #if !UCONFIG_NO_FORMATTING */