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