Home | History | Annotate | Download | only in intltest
      1 /***********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1997-2009, 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 <float.h>
     15 #include <stdlib.h>
     16 
     17 IntlTestNumberFormat::~IntlTestNumberFormat() {}
     18 
     19 static const char * formattableTypeName(Formattable::Type t)
     20 {
     21   switch(t) {
     22   case Formattable::kDate: return "kDate";
     23   case Formattable::kDouble: return "kDouble";
     24   case Formattable::kLong: return "kLong";
     25   case Formattable::kString: return "kString";
     26   case Formattable::kArray: return "kArray";
     27   case Formattable::kInt64: return "kInt64";
     28   default: return "??unknown??";
     29   }
     30 }
     31 
     32 /**
     33  * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
     34  * NumberFormat.
     35  */
     36 void IntlTestNumberFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
     37 {
     38 
     39     if (exec) logln((UnicodeString)"TestSuite NumberFormat");
     40     switch (index) {
     41         case 0: name = "createInstance";
     42             if (exec)
     43             {
     44                 logln(name);
     45                 fStatus = U_ZERO_ERROR;
     46                 fFormat = NumberFormat::createInstance(fStatus);
     47                 testFormat(/*par*/);
     48             }
     49             break;
     50 
     51         case 1: name = "DefaultLocale";
     52             if (exec) testLocale(/*par, */Locale::getDefault(), name);
     53             break;
     54 
     55         case 2: name = "testAvailableLocales";
     56             if (exec) {
     57                 logln(name);
     58                 testAvailableLocales(/*par*/);
     59             }
     60             break;
     61 
     62         case 3: name = "monsterTest";
     63             if (exec) {
     64                 logln(name);
     65                 monsterTest(/*par*/);
     66             }
     67             break;
     68 
     69         default: name = ""; break;
     70     }
     71 }
     72 
     73 void
     74 IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const UnicodeString& localeName)
     75 {
     76     const char* name;
     77 
     78     fLocale = locale;
     79     name = "Number test";
     80     logln((UnicodeString)name + " (" + localeName + ")");
     81     fStatus = U_ZERO_ERROR;
     82     fFormat = NumberFormat::createInstance(locale, fStatus);
     83     testFormat(/* par */);
     84 
     85     name = "Currency test";
     86     logln((UnicodeString)name + " (" + localeName + ")");
     87     fStatus = U_ZERO_ERROR;
     88     fFormat = NumberFormat::createCurrencyInstance(locale, fStatus);
     89     testFormat(/* par */);
     90 
     91     name = "Percent test";
     92     logln((UnicodeString)name + " (" + localeName + ")");
     93     fStatus = U_ZERO_ERROR;
     94     fFormat = NumberFormat::createPercentInstance(locale, fStatus);
     95     testFormat(/* par */);
     96 }
     97 
     98 double IntlTestNumberFormat::randDouble()
     99 {
    100     // Assume 8-bit (or larger) rand values.  Also assume
    101     // that the system rand() function is very poor, which it always is.
    102     // Call srand(currentTime) in intltest to make it truly random.
    103     double d;
    104     uint32_t i;
    105     char* poke = (char*)&d;
    106     do {
    107         for (i=0; i < sizeof(double); ++i)
    108         {
    109             poke[i] = (char)(rand() & 0xFF);
    110         }
    111     } while (uprv_isNaN(d) || uprv_isInfinite(d)
    112         || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
    113 
    114     return d;
    115 }
    116 
    117 /*
    118  * Return a random uint32_t
    119  **/
    120 uint32_t IntlTestNumberFormat::randLong()
    121 {
    122     // Assume 8-bit (or larger) rand values.  Also assume
    123     // that the system rand() function is very poor, which it always is.
    124     // Call srand(currentTime) in intltest to make it truly random.
    125     uint32_t d;
    126     uint32_t i;
    127     char* poke = (char*)&d;
    128     for (i=0; i < sizeof(uint32_t); ++i)
    129     {
    130         poke[i] = (char)(rand() & 0xFF);
    131     }
    132     return d;
    133 }
    134 
    135 
    136 /* Make sure that we don't get something too large and multiply into infinity.
    137    @param smallerThanMax the requested maximum value smaller than DBL_MAX */
    138 double IntlTestNumberFormat::getSafeDouble(double smallerThanMax) {
    139     double it;
    140     double high = (DBL_MAX/smallerThanMax)/10.0;
    141     double low = -high;
    142     do {
    143         it = randDouble();
    144     } while (low > it || it > high);
    145     return it;
    146 }
    147 
    148 void
    149 IntlTestNumberFormat::testFormat(/* char* par */)
    150 {
    151     if (U_FAILURE(fStatus))
    152     {
    153         dataerrln((UnicodeString)"**** FAIL: createXxxInstance failed. - " + u_errorName(fStatus));
    154         if (fFormat != 0)
    155             errln("**** FAIL: Non-null format returned by createXxxInstance upon failure.");
    156         delete fFormat;
    157         fFormat = 0;
    158         return;
    159     }
    160 
    161     if (fFormat == 0)
    162     {
    163         errln((UnicodeString)"**** FAIL: Null format returned by createXxxInstance.");
    164         return;
    165     }
    166 
    167     UnicodeString str;
    168 
    169     // Assume it's a DecimalFormat and get some info
    170     DecimalFormat *s = (DecimalFormat*)fFormat;
    171     logln((UnicodeString)"  Pattern " + s->toPattern(str));
    172 
    173 #if defined(OS390) || defined(OS400)
    174     tryIt(-2.02147304840132e-68);
    175     tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac
    176     tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent
    177     tryIt(9.29526819488338e+64); // Ok -- used to fail?
    178 #else
    179     tryIt(-2.02147304840132e-100);
    180     tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac
    181     tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent
    182     tryIt(9.29526819488338e+250); // Ok -- used to fail?
    183 #endif
    184 
    185     // These PASS now, with the sprintf/atof based format-parse.
    186 
    187     // These fail due to round-off
    188     // The least significant digit drops by one during each format-parse cycle.
    189     // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %)
    190 #ifdef OS390
    191     tryIt(-9.18228054496402e+64);
    192     tryIt(-9.69413034454191e+64);
    193 #else
    194     tryIt(-9.18228054496402e+255);
    195     tryIt(-9.69413034454191e+273);
    196 #endif
    197 
    198 #ifndef OS390
    199     tryIt(1.234e-200);
    200     tryIt(-2.3e-168);
    201 
    202     tryIt(uprv_getNaN());
    203     tryIt(uprv_getInfinity());
    204     tryIt(-uprv_getInfinity());
    205 #endif
    206 
    207     tryIt((int32_t)251887531);
    208     tryIt(5e-20 / 9);
    209     tryIt(5e20 / 9);
    210     tryIt(1.234e-50);
    211     tryIt(9.99999999999996);
    212     tryIt(9.999999999999996);
    213 
    214     tryIt((int32_t)INT32_MIN);
    215     tryIt((int32_t)INT32_MAX);
    216     tryIt((double)INT32_MIN);
    217     tryIt((double)INT32_MAX);
    218     tryIt((double)INT32_MIN - 1.0);
    219     tryIt((double)INT32_MAX + 1.0);
    220 
    221     tryIt(5.0 / 9.0 * 1e-20);
    222     tryIt(4.0 / 9.0 * 1e-20);
    223     tryIt(5.0 / 9.0 * 1e+20);
    224     tryIt(4.0 / 9.0 * 1e+20);
    225 
    226     tryIt(2147483647.);
    227     tryIt((int32_t)0);
    228     tryIt(0.0);
    229     tryIt((int32_t)1);
    230     tryIt((int32_t)10);
    231     tryIt((int32_t)100);
    232     tryIt((int32_t)-1);
    233     tryIt((int32_t)-10);
    234     tryIt((int32_t)-100);
    235     tryIt((int32_t)-1913860352);
    236 
    237     for (int32_t z=0; z<10; ++z)
    238     {
    239         double d = randFraction() * 2e10 - 1e10;
    240         tryIt(d);
    241     }
    242 
    243     double it = getSafeDouble(100000.0);
    244 
    245     tryIt(0.0);
    246     tryIt(it);
    247     tryIt((int32_t)0);
    248     tryIt(uprv_floor(it));
    249     tryIt((int32_t)randLong());
    250 
    251     // try again
    252     it = getSafeDouble(100.0);
    253     tryIt(it);
    254     tryIt(uprv_floor(it));
    255     tryIt((int32_t)randLong());
    256 
    257     // try again with very large numbers
    258     it = getSafeDouble(100000000000.0);
    259     tryIt(it);
    260 
    261     // try again with very large numbers
    262     // and without going outside of the int32_t range
    263     it = randFraction() * INT32_MAX;
    264     tryIt(it);
    265     tryIt((int32_t)uprv_floor(it));
    266 
    267     delete fFormat;
    268 }
    269 
    270 void
    271 IntlTestNumberFormat::tryIt(double aNumber)
    272 {
    273     const int32_t DEPTH = 10;
    274     Formattable number[DEPTH];
    275     UnicodeString string[DEPTH];
    276 
    277     int32_t numberMatch = 0;
    278     int32_t stringMatch = 0;
    279     UnicodeString errMsg;
    280     int32_t i;
    281     for (i=0; i<DEPTH; ++i)
    282     {
    283         errMsg.truncate(0); // if non-empty, we failed this iteration
    284         UErrorCode status = U_ZERO_ERROR;
    285         string[i] = "(n/a)"; // "format was never done" value
    286         if (i == 0) {
    287             number[i].setDouble(aNumber);
    288         } else {
    289             fFormat->parse(string[i-1], number[i], status);
    290             if (U_FAILURE(status)) {
    291                 number[i].setDouble(1234.5); // "parse failed" value
    292                 errMsg = "**** FAIL: Parse of " + prettify(string[i-1]) + " failed.";
    293                 --i; // don't show empty last line: "1234.5 F> (n/a) P>"
    294                 break;
    295             }
    296         }
    297         // Convert from long to double
    298         if (number[i].getType() == Formattable::kLong)
    299             number[i].setDouble(number[i].getLong());
    300         else if (number[i].getType() == Formattable::kInt64)
    301             number[i].setDouble((double)number[i].getInt64());
    302         else if (number[i].getType() != Formattable::kDouble)
    303         {
    304             errMsg = ("**** FAIL: Parse of " + prettify(string[i-1])
    305                 + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number[i].getType()))
    306                 + ", Locale=" + UnicodeString(fLocale.getName())
    307                 + ", longValue=" + number[i].getLong());
    308             break;
    309         }
    310         string[i].truncate(0);
    311         fFormat->format(number[i].getDouble(), string[i]);
    312         if (i > 0)
    313         {
    314             if (numberMatch == 0 && number[i] == number[i-1])
    315                 numberMatch = i;
    316             else if (numberMatch > 0 && number[i] != number[i-1])
    317             {
    318                 errMsg = ("**** FAIL: Numeric mismatch after match.");
    319                 break;
    320             }
    321             if (stringMatch == 0 && string[i] == string[i-1])
    322                 stringMatch = i;
    323             else if (stringMatch > 0 && string[i] != string[i-1])
    324             {
    325                 errMsg = ("**** FAIL: String mismatch after match.");
    326                 break;
    327             }
    328         }
    329         if (numberMatch > 0 && stringMatch > 0)
    330             break;
    331     }
    332     if (i == DEPTH)
    333         --i;
    334 
    335     if (stringMatch > 2 || numberMatch > 2)
    336     {
    337         errMsg = ("**** FAIL: No string and/or number match within 2 iterations.");
    338     }
    339 
    340     if (errMsg.length() != 0)
    341     {
    342         for (int32_t k=0; k<=i; ++k)
    343         {
    344             logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " +
    345                   prettify(string[k]) + " P> ");
    346         }
    347         errln(errMsg);
    348     }
    349 }
    350 
    351 void
    352 IntlTestNumberFormat::tryIt(int32_t aNumber)
    353 {
    354     Formattable number(aNumber);
    355     UnicodeString stringNum;
    356     UErrorCode status = U_ZERO_ERROR;
    357 
    358     fFormat->format(number, stringNum, status);
    359     if (U_FAILURE(status))
    360     {
    361         errln("**** FAIL: Formatting " + aNumber);
    362         return;
    363     }
    364     fFormat->parse(stringNum, number, status);
    365     if (U_FAILURE(status))
    366     {
    367         errln("**** FAIL: Parse of " + prettify(stringNum) + " failed.");
    368         return;
    369     }
    370     if (number.getType() != Formattable::kLong)
    371     {
    372         errln("**** FAIL: Parse of " + prettify(stringNum)
    373             + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number.getType()))
    374             + ", Locale=" + UnicodeString(fLocale.getName())
    375             + ", doubleValue=" + number.getDouble()
    376             + ", longValue=" + number.getLong()
    377             + ", origValue=" + aNumber
    378             );
    379     }
    380     if (number.getLong() != aNumber) {
    381         errln("**** FAIL: Parse of " + prettify(stringNum) + " failed. Got:" + number.getLong()
    382             + " Expected:" + aNumber);
    383     }
    384 }
    385 
    386 void IntlTestNumberFormat::testAvailableLocales(/* char* par */)
    387 {
    388     int32_t count = 0;
    389     const Locale* locales = NumberFormat::getAvailableLocales(count);
    390     logln((UnicodeString)"" + count + " available locales");
    391     if (locales && count)
    392     {
    393         UnicodeString name;
    394         UnicodeString all;
    395         for (int32_t i=0; i<count; ++i)
    396         {
    397             if (i!=0)
    398                 all += ", ";
    399             all += locales[i].getName();
    400         }
    401         logln(all);
    402     }
    403     else
    404         dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
    405 }
    406 
    407 void IntlTestNumberFormat::monsterTest(/* char* par */)
    408 {
    409     const char *SEP = "============================================================\n";
    410     int32_t count;
    411     const Locale* allLocales = NumberFormat::getAvailableLocales(count);
    412     Locale* locales = (Locale*)allLocales;
    413     Locale quickLocales[6];
    414     if (allLocales && count)
    415     {
    416         if (quick && count > 6) {
    417             logln("quick test: testing just 6 locales!");
    418             count = 6;
    419             locales = quickLocales;
    420             locales[0] = allLocales[0];
    421             locales[1] = allLocales[1];
    422             locales[2] = allLocales[2];
    423             // In a quick test, make sure we test locales that use
    424             // currency prefix, currency suffix, and choice currency
    425             // logic.  Otherwise bugs in these areas can slip through.
    426             locales[3] = Locale("ar", "AE", "");
    427             locales[4] = Locale("cs", "CZ", "");
    428             locales[5] = Locale("en", "IN", "");
    429         }
    430         for (int32_t i=0; i<count; ++i)
    431         {
    432             UnicodeString name(locales[i].getName(), "");
    433             logln(SEP);
    434             testLocale(/* par, */locales[i], name);
    435         }
    436     }
    437 
    438     logln(SEP);
    439 }
    440 
    441 #endif /* #if !UCONFIG_NO_FORMATTING */
    442