| /* |
| ***************************************************************************************** |
| * * |
| * COPYRIGHT: * |
| * (C) Copyright Taligent, Inc., 1997 * |
| * (C) Copyright International Business Machines Corporation, 1997-1998 * |
| * Licensed Material - Program-Property of IBM - All Rights Reserved. * |
| * US Government Users Restricted Rights - Use, duplication, or disclosure * |
| * restricted by GSA ADP Schedule Contract with IBM Corp. * |
| * * |
| ***************************************************************************************** |
| */ |
| |
| #include "utypes.h" |
| #include "tsnmfmt.h" |
| |
| #include "decimfmt.h" |
| |
| #include <math.h> |
| #include <float.h> |
| #include <limits.h> |
| |
| /** |
| * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of |
| * NumberFormat. |
| */ |
| void IntlTestNumberFormat::runIndexedTest( int32_t index, bool_t exec, char* &name, char* par ) |
| { |
| |
| if (exec) logln((UnicodeString)"TestSuite NumberFormat"); |
| switch (index) { |
| case 0: name = "createInstance"; |
| if (exec) |
| { |
| logln(name); |
| fStatus = U_ZERO_ERROR; |
| fFormat = NumberFormat::createInstance(fStatus); |
| testFormat(par); |
| } |
| break; |
| |
| case 1: name = "Default Locale"; |
| if (exec) testLocale(par, Locale::getDefault(), "Default Locale"); |
| break; |
| |
| case 2: name = "Determine Available Locales"; |
| if (exec) { |
| logln(name); |
| testAvailableLocales(par); |
| } |
| break; |
| |
| case 3: name = "Test Available Locales"; |
| if (exec) { |
| logln(name); |
| monsterTest(par); |
| } |
| break; |
| |
| default: name = ""; break; |
| } |
| } |
| |
| void |
| IntlTestNumberFormat::testLocale(char* par, const Locale& locale, const UnicodeString& localeName) |
| { |
| const char* name; |
| |
| name = "Number test"; |
| logln((UnicodeString)name + " (" + localeName + ")"); |
| fStatus = U_ZERO_ERROR; |
| fFormat = NumberFormat::createInstance(locale, fStatus); |
| testFormat(par); |
| |
| name = "Currency test"; |
| logln((UnicodeString)name + " (" + localeName + ")"); |
| fStatus = U_ZERO_ERROR; |
| fFormat = NumberFormat::createCurrencyInstance(locale, fStatus); |
| testFormat(par); |
| |
| name = "Percent test"; |
| logln((UnicodeString)name + " (" + localeName + ")"); |
| fStatus = U_ZERO_ERROR; |
| fFormat = NumberFormat::createPercentInstance(locale, fStatus); |
| testFormat(par); |
| } |
| |
| void |
| IntlTestNumberFormat::testFormat(char *par) |
| { |
| if (U_FAILURE(fStatus)) |
| { |
| errln((UnicodeString)"********** FAIL: createXxxInstance failed."); |
| if (fFormat != 0) errln("********** FAIL: Non-null format returned by createXxxInstance upon failure."); |
| delete fFormat; |
| fFormat = 0; |
| return; |
| } |
| |
| if (fFormat == 0) |
| { |
| errln((UnicodeString)"********** FAIL: Null format returned by createXxxInstance."); |
| return; |
| } |
| |
| UnicodeString str; |
| |
| // Assume it's a DecimalFormat and get some info |
| DecimalFormat *s = (DecimalFormat*)fFormat; |
| logln((UnicodeString)" Pattern " + s->toPattern(str)); |
| |
| if (1) |
| { |
| tryIt(-2.02147304840132e-100); |
| tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac |
| tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent |
| tryIt(9.29526819488338e+250); // Ok -- used to fail? |
| } |
| |
| if (1) |
| { |
| // These PASS now, with the sprintf/atof based format-parse. |
| |
| // These fail due to round-off |
| // The least significant digit drops by one during each format-parse cycle. |
| // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %) |
| tryIt(-9.18228054496402e+255); |
| tryIt(-9.69413034454191e+273); |
| } |
| |
| if (1) |
| { |
| tryIt(T_INT32(251887531)); |
| tryIt(-2.3e-168); |
| |
| tryIt(icu_getNaN()); |
| tryIt(icu_getInfinity()); |
| tryIt(-icu_getInfinity()); |
| |
| tryIt(5e-20 / 9); |
| tryIt(5e20 / 9); |
| tryIt(1.234e-200); |
| tryIt(1.234e-50); |
| tryIt(9.99999999999996); |
| tryIt(9.999999999999996); |
| |
| tryIt((int32_t)LONG_MIN); |
| tryIt((int32_t)LONG_MAX); |
| tryIt((double)LONG_MIN); |
| tryIt((double)LONG_MAX); |
| tryIt((double)LONG_MIN - 1.0); |
| tryIt((double)LONG_MAX + 1.0); |
| |
| tryIt(5.0 / 9.0 * 1e-20); |
| tryIt(4.0 / 9.0 * 1e-20); |
| tryIt(5.0 / 9.0 * 1e+20); |
| tryIt(4.0 / 9.0 * 1e+20); |
| |
| tryIt(2147483647.); |
| tryIt(T_INT32(0)); |
| tryIt(0.0); |
| tryIt((int32_t)1); |
| tryIt((int32_t)10); |
| tryIt((int32_t)100); |
| tryIt((int32_t)-1); |
| tryIt((int32_t)-10); |
| tryIt((int32_t)-100); |
| } |
| |
| if (1) |
| { |
| for (int32_t z=0; z<10; ++z) |
| { |
| double d = randFraction() * 2e10 - 1e10; |
| tryIt(d); |
| } |
| |
| double it = randDouble() * 10000; |
| tryIt(0.0); |
| tryIt(it); |
| tryIt(T_INT32(0)); |
| tryIt(T_INT32(icu_floor(it))); |
| |
| // try again |
| it = randDouble() * 10; |
| tryIt(it); |
| tryIt(T_INT32(icu_floor(it))); |
| |
| // try again with very larget numbers |
| it = randDouble() * 10000000000.0; |
| tryIt(it); |
| tryIt(T_INT32(icu_floor(it))); |
| } |
| |
| delete fFormat; |
| } |
| |
| void |
| IntlTestNumberFormat::tryIt(double aNumber) |
| { |
| const int32_t DEPTH = 10; |
| Formattable number[DEPTH]; |
| UnicodeString string[DEPTH]; |
| |
| int32_t numberMatch = 0; |
| int32_t stringMatch = 0; |
| bool_t dump = FALSE; |
| int32_t i; |
| for (i=0; i<DEPTH; ++i) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| if (i == 0) number[i].setDouble(aNumber); |
| else fFormat->parse(string[i-1], number[i], status); |
| if (U_FAILURE(status)) |
| { |
| errln("********** FAIL: Parse of " + string[i-1] + " failed."); |
| dump = TRUE; |
| break; |
| } |
| // Convert from long to double |
| if (number[i].getType() == Formattable::kLong) number[i].setDouble(number[i].getLong()); |
| else if (number[i].getType() != Formattable::kDouble) |
| { |
| errln("********** FAIL: Parse of " + string[i-1] + " returned non-numeric Formattable."); |
| dump = TRUE; |
| break; |
| } |
| fFormat->format(number[i].getDouble(), string[i]); |
| if (i > 0) |
| { |
| if (numberMatch == 0 && number[i] == number[i-1]) numberMatch = i; |
| else if (numberMatch > 0 && number[i] != number[i-1]) |
| { |
| errln("********** FAIL: Numeric mismatch after match."); |
| dump = TRUE; |
| break; |
| } |
| if (stringMatch == 0 && string[i] == string[i-1]) stringMatch = i; |
| else if (stringMatch > 0 && string[i] != string[i-1]) |
| { |
| errln("********** FAIL: String mismatch after match."); |
| dump = TRUE; |
| break; |
| } |
| } |
| if (numberMatch > 0 && stringMatch > 0) break; |
| } |
| if (i == DEPTH) --i; |
| |
| if (stringMatch > 2 || numberMatch > 2) |
| { |
| errln("********** FAIL: No string and/or number match within 2 iterations."); |
| dump = TRUE; |
| } |
| |
| if (dump) |
| { |
| for (int32_t k=0; k<=i; ++k) |
| { |
| logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " + |
| string[k] + " P> "); |
| } |
| } |
| } |
| |
| void |
| IntlTestNumberFormat::tryIt(int32_t aNumber) |
| { |
| const int32_t DEPTH = 10; |
| Formattable number[DEPTH]; |
| UnicodeString string[DEPTH]; |
| |
| int32_t numberMatch = 0; |
| int32_t stringMatch = 0; |
| bool_t dump = FALSE; |
| int32_t i; |
| for (i=0; i<DEPTH; ++i) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| if (i == 0) number[i].setLong(aNumber); |
| else fFormat->parse(string[i-1], number[i], status); |
| if (U_FAILURE(status)) |
| { |
| errln("********** FAIL: Parse of " + string[i-1] + " failed."); |
| dump = TRUE; |
| break; |
| } |
| if (number[i].getType() != Formattable::kLong) |
| { |
| errln("********** FAIL: Parse of " + string[i-1] + " returned non-long Formattable."); |
| dump = TRUE; |
| break; |
| } |
| fFormat->format(number[i].getLong(), string[i]); |
| if (i > 0) |
| { |
| if (numberMatch == 0 && number[i] == number[i-1]) numberMatch = i; |
| else if (numberMatch > 0 && number[i] != number[i-1]) |
| { |
| errln("********** FAIL: Numeric mismatch after match."); |
| dump = TRUE; |
| break; |
| } |
| if (stringMatch == 0 && string[i] == string[i-1]) stringMatch = i; |
| else if (stringMatch > 0 && string[i] != string[i-1]) |
| { |
| errln("********** FAIL: String mismatch after match."); |
| dump = TRUE; |
| break; |
| } |
| } |
| if (numberMatch > 0 && stringMatch > 0) break; |
| } |
| if (i == DEPTH) --i; |
| |
| if (stringMatch > 2 || numberMatch > 2) |
| { |
| errln("********** FAIL: No string and/or number match within 2 iterations."); |
| dump = TRUE; |
| } |
| |
| if (dump) |
| { |
| for (int32_t k=0; k<=i; ++k) |
| { |
| logln((UnicodeString)"" + k + ": " + number[k].getLong() + " F> " + |
| string[k] + " P> "); |
| } |
| } |
| } |
| |
| void IntlTestNumberFormat::testAvailableLocales(char *par) |
| { |
| int32_t count = 0; |
| const Locale* locales = NumberFormat::getAvailableLocales(count); |
| logln((UnicodeString)"" + count + " available locales"); |
| if (locales && count) |
| { |
| UnicodeString name; |
| UnicodeString all; |
| for (int32_t i=0; i<count; ++i) |
| { |
| if (i!=0) all += ", "; |
| all += locales[i].getName(name); |
| } |
| logln(all); |
| } |
| else errln((UnicodeString)"********** FAIL: Zero available locales or null array pointer"); |
| } |
| |
| void IntlTestNumberFormat::monsterTest(char *par) |
| { |
| const char *SEP = "============================================================\n"; |
| int32_t count; |
| const Locale* locales = NumberFormat::getAvailableLocales(count); |
| if (locales && count) |
| { |
| if (quick && count > 2) { |
| logln("quick test: testing just 2 locales!"); |
| count = 2; |
| } |
| for (int32_t i=0; i<count; ++i) |
| { |
| UnicodeString name; |
| locales[i].getName(name); |
| logln(SEP); |
| testLocale(par, locales[i], name); |
| } |
| } |
| |
| logln(SEP); |
| } |