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 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 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_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 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 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 #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]) + " 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 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(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 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 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