diff options
Diffstat (limited to 'Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp')
-rw-r--r-- | Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp b/Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp new file mode 100644 index 00000000000..d05b96bbb9a --- /dev/null +++ b/Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp @@ -0,0 +1,452 @@ +/*********************************************************************** + * COPYRIGHT: + * Copyright (c) 1997-2011, International Business Machines Corporation + * and others. All Rights Reserved. + ***********************************************************************/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/decimfmt.h" +#include "tsnmfmt.h" +#include "putilimp.h" +#include "cstring.h" +#include <float.h> +#include <stdlib.h> + +IntlTestNumberFormat::~IntlTestNumberFormat() {} + +static const char * formattableTypeName(Formattable::Type t) +{ + switch(t) { + case Formattable::kDate: return "kDate"; + case Formattable::kDouble: return "kDouble"; + case Formattable::kLong: return "kLong"; + case Formattable::kString: return "kString"; + case Formattable::kArray: return "kArray"; + case Formattable::kInt64: return "kInt64"; + default: return "??unknown??"; + } +} + +/** + * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of + * NumberFormat. + */ +void IntlTestNumberFormat::runIndexedTest( int32_t index, UBool exec, const 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 = "DefaultLocale"; + if (exec) testLocale(/*par, */Locale::getDefault(), name); + break; + + case 2: name = "testAvailableLocales"; + if (exec) { + logln(name); + testAvailableLocales(/*par*/); + } + break; + + case 3: name = "monsterTest"; + if (exec) { + logln(name); + monsterTest(/*par*/); + } + break; + + default: name = ""; break; + } +} + +void +IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const UnicodeString& localeName) +{ + const char* name; + + fLocale = locale; + 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 */); + + if (uprv_strcmp(locale.getName(), "en_US_POSIX") != 0) { + name = "Scientific test"; + logln((UnicodeString)name + " (" + localeName + ")"); + fStatus = U_ZERO_ERROR; + fFormat = NumberFormat::createScientificInstance(locale, fStatus); + testFormat(/* par */); + } +} + +double IntlTestNumberFormat::randDouble() +{ + // Assume 8-bit (or larger) rand values. Also assume + // that the system rand() function is very poor, which it always is. + // Call srand(currentTime) in intltest to make it truly random. + double d; + uint32_t i; + char* poke = (char*)&d; + do { + for (i=0; i < sizeof(double); ++i) + { + poke[i] = (char)(rand() & 0xFF); + } + } while (uprv_isNaN(d) || uprv_isInfinite(d) + || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d))); + + return d; +} + +/* + * Return a random uint32_t + **/ +uint32_t IntlTestNumberFormat::randLong() +{ + // Assume 8-bit (or larger) rand values. Also assume + // that the system rand() function is very poor, which it always is. + // Call srand(currentTime) in intltest to make it truly random. + uint32_t d; + uint32_t i; + char* poke = (char*)&d; + for (i=0; i < sizeof(uint32_t); ++i) + { + poke[i] = (char)(rand() & 0xFF); + } + return d; +} + + +/* Make sure that we don't get something too large and multiply into infinity. + @param smallerThanMax the requested maximum value smaller than DBL_MAX */ +double IntlTestNumberFormat::getSafeDouble(double smallerThanMax) { + double it; + double high = (DBL_MAX/smallerThanMax)/10.0; + double low = -high; + do { + it = randDouble(); + } while (low > it || it > high); + return it; +} + +void +IntlTestNumberFormat::testFormat(/* char* par */) +{ + if (U_FAILURE(fStatus)) + { + dataerrln((UnicodeString)"**** FAIL: createXxxInstance failed. - " + u_errorName(fStatus)); + 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 defined(OS390) || defined(OS400) + tryIt(-2.02147304840132e-68); + tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac + tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent + tryIt(9.29526819488338e+64); // Ok -- used to fail? +#else + 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? +#endif + + // 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 %) +#ifdef OS390 + tryIt(-9.18228054496402e+64); + tryIt(-9.69413034454191e+64); +#else + tryIt(-9.18228054496402e+255); + tryIt(-9.69413034454191e+273); +#endif + +#ifndef OS390 + tryIt(1.234e-200); + tryIt(-2.3e-168); + + tryIt(uprv_getNaN()); + tryIt(uprv_getInfinity()); + tryIt(-uprv_getInfinity()); +#endif + + tryIt((int32_t)251887531); + tryIt(5e-20 / 9); + tryIt(5e20 / 9); + tryIt(1.234e-50); + tryIt(9.99999999999996); + tryIt(9.999999999999996); + + tryIt(5.06e-27); + + tryIt((int32_t)INT32_MIN); + tryIt((int32_t)INT32_MAX); + tryIt((double)INT32_MIN); + tryIt((double)INT32_MAX); + tryIt((double)INT32_MIN - 1.0); + tryIt((double)INT32_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((int32_t)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); + tryIt((int32_t)-1913860352); + + for (int32_t z=0; z<10; ++z) + { + double d = randFraction() * 2e10 - 1e10; + tryIt(d); + } + + double it = getSafeDouble(100000.0); + + tryIt(0.0); + tryIt(it); + tryIt((int32_t)0); + tryIt(uprv_floor(it)); + tryIt((int32_t)randLong()); + + // try again + it = getSafeDouble(100.0); + tryIt(it); + tryIt(uprv_floor(it)); + tryIt((int32_t)randLong()); + + // try again with very large numbers + it = getSafeDouble(100000000000.0); + tryIt(it); + + // try again with very large numbers + // and without going outside of the int32_t range + it = randFraction() * INT32_MAX; + tryIt(it); + tryIt((int32_t)uprv_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; + UnicodeString errMsg; + int32_t i; + for (i=0; i<DEPTH; ++i) + { + errMsg.truncate(0); // if non-empty, we failed this iteration + UErrorCode status = U_ZERO_ERROR; + string[i] = "(n/a)"; // "format was never done" value + if (i == 0) { + number[i].setDouble(aNumber); + } else { + fFormat->parse(string[i-1], number[i], status); + if (U_FAILURE(status)) { + number[i].setDouble(1234.5); // "parse failed" value + errMsg = "**** FAIL: Parse of " + prettify(string[i-1]) + " failed."; + --i; // don't show empty last line: "1234.5 F> (n/a) P>" + break; + } + } + // Convert from long to double + if (number[i].getType() == Formattable::kLong) + number[i].setDouble(number[i].getLong()); + else if (number[i].getType() == Formattable::kInt64) + number[i].setDouble((double)number[i].getInt64()); + else if (number[i].getType() != Formattable::kDouble) + { + errMsg = ("**** FAIL: Parse of " + prettify(string[i-1]) + + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number[i].getType())) + + ", Locale=" + UnicodeString(fLocale.getName()) + + ", longValue=" + number[i].getLong()); + break; + } + string[i].truncate(0); + 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]) + { + errMsg = ("**** FAIL: Numeric mismatch after match."); + break; + } + if (stringMatch == 0 && string[i] == string[i-1]) + stringMatch = i; + else if (stringMatch > 0 && string[i] != string[i-1]) + { + errMsg = ("**** FAIL: String mismatch after match."); + break; + } + } + if (numberMatch > 0 && stringMatch > 0) + break; + } + if (i == DEPTH) + --i; + + if (stringMatch > 2 || numberMatch > 2) + { + errMsg = ("**** FAIL: No string and/or number match within 2 iterations."); + } + + if (errMsg.length() != 0) + { + for (int32_t k=0; k<=i; ++k) + { + logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " + + prettify(string[k]) + " P> "); + } + errln(errMsg); + } +} + +void +IntlTestNumberFormat::tryIt(int32_t aNumber) +{ + Formattable number(aNumber); + UnicodeString stringNum; + UErrorCode status = U_ZERO_ERROR; + + fFormat->format(number, stringNum, status); + if (U_FAILURE(status)) + { + errln("**** FAIL: Formatting " + aNumber); + return; + } + fFormat->parse(stringNum, number, status); + if (U_FAILURE(status)) + { + errln("**** FAIL: Parse of " + prettify(stringNum) + " failed."); + return; + } + if (number.getType() != Formattable::kLong) + { + errln("**** FAIL: Parse of " + prettify(stringNum) + + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number.getType())) + + ", Locale=" + UnicodeString(fLocale.getName()) + + ", doubleValue=" + number.getDouble() + + ", longValue=" + number.getLong() + + ", origValue=" + aNumber + ); + } + if (number.getLong() != aNumber) { + errln("**** FAIL: Parse of " + prettify(stringNum) + " failed. Got:" + number.getLong() + + " Expected:" + aNumber); + } +} + +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(); + } + logln(all); + } + else + dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer"); +} + +void IntlTestNumberFormat::monsterTest(/* char* par */) +{ + const char *SEP = "============================================================\n"; + int32_t count; + const Locale* allLocales = NumberFormat::getAvailableLocales(count); + Locale* locales = (Locale*)allLocales; + Locale quickLocales[6]; + if (allLocales && count) + { + if (quick && count > 6) { + logln("quick test: testing just 6 locales!"); + count = 6; + locales = quickLocales; + locales[0] = allLocales[0]; + locales[1] = allLocales[1]; + locales[2] = allLocales[2]; + // In a quick test, make sure we test locales that use + // currency prefix, currency suffix, and choice currency + // logic. Otherwise bugs in these areas can slip through. + locales[3] = Locale("ar", "AE", ""); + locales[4] = Locale("cs", "CZ", ""); + locales[5] = Locale("en", "IN", ""); + } + for (int32_t i=0; i<count; ++i) + { + UnicodeString name(locales[i].getName(), ""); + logln(SEP); + testLocale(/* par, */locales[i], name); + } + } + + logln(SEP); +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ |