3aaa52af8d
X-SVN-Rev: 596
366 lines
10 KiB
C++
366 lines
10 KiB
C++
/********************************************************************
|
|
* COPYRIGHT:
|
|
* Copyright (c) 1997-1999, International Business Machines Corporation and
|
|
* others. All Rights Reserved.
|
|
********************************************************************/
|
|
|
|
#include "unicode/utypes.h"
|
|
#include "tsnmfmt.h"
|
|
|
|
#include "unicode/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(uprv_getNaN());
|
|
tryIt(uprv_getInfinity());
|
|
tryIt(-uprv_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(uprv_floor(it)));
|
|
|
|
// try again
|
|
it = randDouble() * 10;
|
|
tryIt(it);
|
|
tryIt(T_INT32(uprv_floor(it)));
|
|
|
|
// try again with very larget numbers
|
|
it = randDouble() * 10000000000.0;
|
|
tryIt(it);
|
|
tryIt(T_INT32(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;
|
|
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);
|
|
}
|