summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-4.8.1/test/intltest/tsnmfmt.cpp
diff options
context:
space:
mode:
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.cpp452
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 */