| OLD | NEW |
| (Empty) |
| 1 /*********************************************************************** | |
| 2 * COPYRIGHT: | |
| 3 * Copyright (c) 1997-2012, 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 | |
| 18 IntlTestNumberFormat::~IntlTestNumberFormat() {} | |
| 19 | |
| 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 */ | |
| 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 | |
| 75 IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const Uni
codeString& 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 | |
| 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 **/ | |
| 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 */ | |
| 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 | |
| 158 IntlTestNumberFormat::testFormat(/* char* par */) | |
| 159 { | |
| 160 if (U_FAILURE(fStatus)) | |
| 161 { | |
| 162 dataerrln((UnicodeString)"**** FAIL: createXxxInstance failed. - " + u_e
rrorName(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 createXxxInstan
ce."); | |
| 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 U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400 | |
| 183 tryIt(-2.02147304840132e-68); | |
| 184 tryIt(3.88057859588817e-68); // Test rounding when only some digits are show
n 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 sho
wn 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! (show
n as %) | |
| 199 #if U_PLATFORM == U_PF_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 #if U_PLATFORM != U_PF_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 | |
| 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]) + " fail
ed."; | |
| 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(for
mattableTypeName(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 | |
| 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(UnicodeString("**** 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(formattabl
eTypeName(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:" + n
umber.getLong() | |
| 393 + " Expected:" + aNumber); | |
| 394 } | |
| 395 } | |
| 396 | |
| 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 arra
y pointer"); | |
| 416 } | |
| 417 | |
| 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 */ | |
| OLD | NEW |