Home | History | Annotate | Download | only in cintltst
      1 //  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-2016, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  ********************************************************************/
      8 /********************************************************************************
      9 *
     10 * File CNUMTST.C
     11 *
     12 *     Madhu Katragadda              Creation
     13 *
     14 * Modification History:
     15 *
     16 *   Date        Name        Description
     17 *   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
     18 *   07/15/99    helena      Ported to HPUX 10/11 CC.
     19 *********************************************************************************
     20 */
     21 
     22 /* C API TEST FOR NUMBER FORMAT */
     23 
     24 #include "unicode/utypes.h"
     25 
     26 #if !UCONFIG_NO_FORMATTING
     27 
     28 #include "unicode/uloc.h"
     29 #include "unicode/umisc.h"
     30 #include "unicode/unum.h"
     31 #include "unicode/unumsys.h"
     32 #include "unicode/ustring.h"
     33 #include "unicode/udisplaycontext.h"
     34 
     35 #include "cintltst.h"
     36 #include "cnumtst.h"
     37 #include "cmemory.h"
     38 #include "cstring.h"
     39 #include "putilimp.h"
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 
     43 static const char *tagAssert(const char *f, int32_t l, const char *msg) {
     44     static char _fileline[1000];
     45     sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg);
     46     return _fileline;
     47 }
     48 
     49 #define ASSERT_TRUE(x)   assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
     50 
     51 void addNumForTest(TestNode** root);
     52 static void TestTextAttributeCrash(void);
     53 static void TestNBSPInPattern(void);
     54 static void TestInt64Parse(void);
     55 static void TestParseCurrency(void);
     56 static void TestMaxInt(void);
     57 static void TestNoExponent(void);
     58 static void TestUFormattable(void);
     59 static void TestUNumberingSystem(void);
     60 static void TestCurrencyIsoPluralFormat(void);
     61 static void TestContext(void);
     62 static void TestCurrencyUsage(void);
     63 static void TestCurrFmtNegSameAsPositive(void);
     64 static void TestVariousStylesAndAttributes(void);
     65 static void TestParseCurrPatternWithDecStyle(void);
     66 static void TestFormatForFields(void);
     67 static void TestRBNFRounding(void);
     68 
     69 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
     70 
     71 void addNumForTest(TestNode** root)
     72 {
     73     TESTCASE(TestNumberFormat);
     74     TESTCASE(TestSpelloutNumberParse);
     75     TESTCASE(TestSignificantDigits);
     76     TESTCASE(TestSigDigRounding);
     77     TESTCASE(TestNumberFormatPadding);
     78     TESTCASE(TestInt64Format);
     79     TESTCASE(TestNonExistentCurrency);
     80     TESTCASE(TestCurrencyRegression);
     81     TESTCASE(TestTextAttributeCrash);
     82     TESTCASE(TestRBNFFormat);
     83     TESTCASE(TestRBNFRounding);
     84     TESTCASE(TestNBSPInPattern);
     85     TESTCASE(TestInt64Parse);
     86     TESTCASE(TestParseZero);
     87     TESTCASE(TestParseCurrency);
     88     TESTCASE(TestCloneWithRBNF);
     89     TESTCASE(TestMaxInt);
     90     TESTCASE(TestNoExponent);
     91     TESTCASE(TestUFormattable);
     92     TESTCASE(TestUNumberingSystem);
     93     TESTCASE(TestCurrencyIsoPluralFormat);
     94     TESTCASE(TestContext);
     95     TESTCASE(TestCurrencyUsage);
     96     TESTCASE(TestCurrFmtNegSameAsPositive);
     97     TESTCASE(TestVariousStylesAndAttributes);
     98     TESTCASE(TestParseCurrPatternWithDecStyle);
     99     TESTCASE(TestFormatForFields);
    100 }
    101 
    102 /* test Parse int 64 */
    103 
    104 static void TestInt64Parse()
    105 {
    106 
    107     UErrorCode st = U_ZERO_ERROR;
    108     UErrorCode* status = &st;
    109 
    110     const char* st1 = "009223372036854775808";
    111     const int size = 21;
    112     UChar text[21];
    113 
    114 
    115     UNumberFormat* nf;
    116 
    117     int64_t a;
    118 
    119     u_charsToUChars(st1, text, size);
    120     nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status);
    121 
    122     if(U_FAILURE(*status))
    123     {
    124         log_data_err("Error in unum_open() %s \n", myErrorName(*status));
    125         return;
    126     }
    127 
    128     log_verbose("About to test unum_parseInt64() with out of range number\n");
    129 
    130     a = unum_parseInt64(nf, text, size, 0, status);
    131     (void)a;     /* Suppress set but not used warning. */
    132 
    133 
    134     if(!U_FAILURE(*status))
    135     {
    136         log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status));
    137     }
    138     else
    139     {
    140         log_verbose("unum_parseInt64() successful\n");
    141     }
    142 
    143     unum_close(nf);
    144     return;
    145 }
    146 
    147 /* test Number Format API */
    148 static void TestNumberFormat()
    149 {
    150     UChar *result=NULL;
    151     UChar temp1[512];
    152     UChar temp2[512];
    153 
    154     UChar temp[5];
    155 
    156     UChar prefix[5];
    157     UChar suffix[5];
    158     UChar symbol[20];
    159     int32_t resultlength;
    160     int32_t resultlengthneeded;
    161     int32_t parsepos;
    162     double d1 = -1.0;
    163     int32_t l1;
    164     double d = -10456.37;
    165     double a = 1234.56, a1 = 1235.0;
    166     int32_t l = 100000000;
    167     UFieldPosition pos1;
    168     UFieldPosition pos2;
    169     int32_t numlocales;
    170     int32_t i;
    171 
    172     UNumberFormatAttribute attr;
    173     UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL;
    174     int32_t newvalue;
    175     UErrorCode status=U_ZERO_ERROR;
    176     UNumberFormatStyle style= UNUM_DEFAULT;
    177     UNumberFormat *pattern;
    178     UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr,
    179                   *cur_frpattern, *myclone, *spellout_def;
    180 
    181     /* Testing unum_open() with various Numberformat styles and locales*/
    182     status = U_ZERO_ERROR;
    183     log_verbose("Testing  unum_open() with default style and locale\n");
    184     def=unum_open(style, NULL,0,NULL, NULL,&status);
    185 
    186     /* Might as well pack it in now if we can't even get a default NumberFormat... */
    187     if(U_FAILURE(status))
    188     {
    189         log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
    190         return;
    191     }
    192 
    193     log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
    194     fr=unum_open(style,NULL,0, "fr_FR",NULL, &status);
    195     if(U_FAILURE(status))
    196         log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status));
    197 
    198     log_verbose("\nTesting unum_open(currency,NULL,status)\n");
    199     style=UNUM_CURRENCY;
    200     /* Can't hardcode the result to assume the default locale is "en_US". */
    201     cur_def=unum_open(style, NULL,0,"en_US", NULL, &status);
    202     if(U_FAILURE(status))
    203         log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
    204                         myErrorName(status) );
    205 
    206     log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
    207     cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status);
    208     if(U_FAILURE(status))
    209         log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
    210                 myErrorName(status));
    211 
    212     log_verbose("\nTesting unum_open(percent, NULL, status)\n");
    213     style=UNUM_PERCENT;
    214     per_def=unum_open(style,NULL,0, NULL,NULL, &status);
    215     if(U_FAILURE(status))
    216         log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status));
    217 
    218     log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
    219     per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status);
    220     if(U_FAILURE(status))
    221         log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status));
    222 
    223     log_verbose("\nTesting unum_open(spellout, NULL, status)");
    224     style=UNUM_SPELLOUT;
    225     spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status);
    226     if(U_FAILURE(status))
    227         log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status));
    228 
    229     /* Testing unum_clone(..) */
    230     log_verbose("\nTesting unum_clone(fmt, status)");
    231     status = U_ZERO_ERROR;
    232     myclone = unum_clone(def,&status);
    233     if(U_FAILURE(status))
    234         log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status));
    235     else
    236     {
    237         log_verbose("unum_clone() successful\n");
    238     }
    239 
    240     /*Testing unum_getAvailable() and unum_countAvailable()*/
    241     log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
    242     numlocales=unum_countAvailable();
    243     if(numlocales < 0)
    244         log_err("error in countAvailable");
    245     else{
    246         log_verbose("unum_countAvialable() successful\n");
    247         log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales);
    248     }
    249     for(i=0;i<numlocales;i++)
    250     {
    251         log_verbose("%s\n", unum_getAvailable(i));
    252         if (unum_getAvailable(i) == 0)
    253             log_err("No locale for which number formatting patterns are applicable\n");
    254         else
    255             log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i));
    256     }
    257 
    258 
    259     /*Testing unum_format() and unum_formatdouble()*/
    260     u_uastrcpy(temp1, "$100,000,000.00");
    261 
    262     log_verbose("\nTesting unum_format() \n");
    263     resultlength=0;
    264     pos1.field = UNUM_INTEGER_FIELD;
    265     resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
    266     if(status==U_BUFFER_OVERFLOW_ERROR)
    267     {
    268         status=U_ZERO_ERROR;
    269         resultlength=resultlengthneeded+1;
    270         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    271 /*        for (i = 0; i < 100000; i++) */
    272         {
    273             unum_format(cur_def, l, result, resultlength, &pos1, &status);
    274         }
    275     }
    276 
    277     if(U_FAILURE(status))
    278     {
    279         log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) );
    280     }
    281     if(u_strcmp(result, temp1)==0)
    282         log_verbose("Pass: Number formatting using unum_format() successful\n");
    283     else
    284         log_err("Fail: Error in number Formatting using unum_format()\n");
    285     if(pos1.beginIndex == 1 && pos1.endIndex == 12)
    286         log_verbose("Pass: Complete number formatting using unum_format() successful\n");
    287     else
    288         log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
    289                 pos1.beginIndex, pos1.endIndex);
    290 
    291     free(result);
    292     result = 0;
    293 
    294     log_verbose("\nTesting unum_formatDouble()\n");
    295     u_uastrcpy(temp1, "-$10,456.37");
    296     resultlength=0;
    297     pos2.field = UNUM_FRACTION_FIELD;
    298     resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status);
    299     if(status==U_BUFFER_OVERFLOW_ERROR)
    300     {
    301         status=U_ZERO_ERROR;
    302         resultlength=resultlengthneeded+1;
    303         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    304 /*        for (i = 0; i < 100000; i++) */
    305         {
    306             unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status);
    307         }
    308     }
    309     if(U_FAILURE(status))
    310     {
    311         log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
    312     }
    313     if(result && u_strcmp(result, temp1)==0)
    314         log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
    315     else {
    316       log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
    317               aescstrdup(result, -1), aescstrdup(temp1, -1));
    318     }
    319     if(pos2.beginIndex == 9 && pos2.endIndex == 11)
    320         log_verbose("Pass: Complete number formatting using unum_format() successful\n");
    321     else
    322         log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
    323                 pos1.beginIndex, pos1.endIndex);
    324 
    325 
    326     /* Testing unum_parse() and unum_parseDouble() */
    327     log_verbose("\nTesting unum_parseDouble()\n");
    328 /*    for (i = 0; i < 100000; i++)*/
    329     parsepos=0;
    330     if (result != NULL) {
    331       d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status);
    332     } else {
    333       log_err("result is NULL\n");
    334     }
    335     if(U_FAILURE(status)) {
    336       log_err("parse of '%s' failed. Parsepos=%d. The error is  : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status));
    337     }
    338 
    339     if(d1!=d)
    340         log_err("Fail: Error in parsing\n");
    341     else
    342         log_verbose("Pass: parsing successful\n");
    343     if (result)
    344         free(result);
    345     result = 0;
    346 
    347     status = U_ZERO_ERROR;
    348     /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
    349     log_verbose("\nTesting unum_formatDoubleCurrency\n");
    350     u_uastrcpy(temp1, "Y1,235");
    351     temp1[0] = 0xA5; /* Yen sign */
    352     u_uastrcpy(temp, "JPY");
    353     resultlength=0;
    354     pos2.field = UNUM_INTEGER_FIELD;
    355     resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status);
    356     if (status==U_BUFFER_OVERFLOW_ERROR) {
    357         status=U_ZERO_ERROR;
    358         resultlength=resultlengthneeded+1;
    359         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    360         unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status);
    361     }
    362     if (U_FAILURE(status)) {
    363         log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
    364     }
    365     if (result && u_strcmp(result, temp1)==0) {
    366         log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
    367     } else {
    368         log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
    369                 aescstrdup(result, -1), aescstrdup(temp1, -1));
    370     }
    371     if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
    372         log_verbose("Pass: Complete number formatting using unum_format() successful\n");
    373     } else {
    374         log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
    375                 pos1.beginIndex, pos1.endIndex);
    376     }
    377 
    378     log_verbose("\nTesting unum_parseDoubleCurrency\n");
    379     parsepos=0;
    380     if (result == NULL) {
    381         log_err("result is NULL\n");
    382     }
    383     else {
    384         d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
    385         if (U_FAILURE(status)) {
    386           log_err("parseDoubleCurrency '%s' failed. The error is  : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
    387         }
    388         /* Note: a==1234.56, but on parse expect a1=1235.0 */
    389         if (d1!=a1) {
    390             log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1);
    391         } else {
    392             log_verbose("Pass: parsed currency amount successfully\n");
    393         }
    394         if (u_strcmp(temp2, temp)==0) {
    395             log_verbose("Pass: parsed correct currency\n");
    396         } else {
    397             log_err("Fail: parsed incorrect currency\n");
    398         }
    399     }
    400     status = U_ZERO_ERROR; /* reset */
    401 
    402     free(result);
    403     result = 0;
    404 
    405 
    406 /* performance testing */
    407     u_uastrcpy(temp1, "$462.12345");
    408     resultlength=u_strlen(temp1);
    409 /*    for (i = 0; i < 100000; i++) */
    410     {
    411         parsepos=0;
    412         d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status);
    413     }
    414     if(U_FAILURE(status))
    415     {
    416         log_err("parseDouble('%s') failed. The error is  : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
    417     }
    418 
    419     /*
    420      * Note: "for strict standard conformance all operations and constants are now supposed to be
    421               evaluated in precision of long double".  So,  we assign a1 before comparing to a double. Bug #7932.
    422      */
    423     a1 = 462.12345;
    424 
    425     if(d1!=a1)
    426         log_err("Fail: Error in parsing\n");
    427     else
    428         log_verbose("Pass: parsing successful\n");
    429 
    430 free(result);
    431 
    432     u_uastrcpy(temp1, "($10,456.3E1])");
    433     parsepos=0;
    434     d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status);
    435     if(U_SUCCESS(status))
    436     {
    437         log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status));
    438     }
    439 
    440 
    441     log_verbose("\nTesting unum_format()\n");
    442     status=U_ZERO_ERROR;
    443     resultlength=0;
    444     parsepos=0;
    445     resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status);
    446     if(status==U_BUFFER_OVERFLOW_ERROR)
    447     {
    448         status=U_ZERO_ERROR;
    449         resultlength=resultlengthneeded+1;
    450         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    451 /*        for (i = 0; i < 100000; i++)*/
    452         {
    453             unum_format(per_fr, l, result, resultlength, &pos1, &status);
    454         }
    455     }
    456     if(U_FAILURE(status))
    457     {
    458         log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
    459     }
    460 
    461 
    462     log_verbose("\nTesting unum_parse()\n");
    463 /*    for (i = 0; i < 100000; i++) */
    464     {
    465         parsepos=0;
    466         l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status);
    467     }
    468     if(U_FAILURE(status))
    469     {
    470         log_err("parse failed. The error is  : %s\n", myErrorName(status));
    471     }
    472 
    473     if(l1!=l)
    474         log_err("Fail: Error in parsing\n");
    475     else
    476         log_verbose("Pass: parsing successful\n");
    477 
    478 free(result);
    479 
    480     /* create a number format using unum_openPattern(....)*/
    481     log_verbose("\nTesting unum_openPattern()\n");
    482     u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)");
    483     pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
    484     if(U_FAILURE(status))
    485     {
    486         log_err("error in unum_openPattern(): %s\n", myErrorName(status) );;
    487     }
    488     else
    489         log_verbose("Pass: unum_openPattern() works fine\n");
    490 
    491     /*test for unum_toPattern()*/
    492     log_verbose("\nTesting unum_toPattern()\n");
    493     resultlength=0;
    494     resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
    495     if(status==U_BUFFER_OVERFLOW_ERROR)
    496     {
    497         status=U_ZERO_ERROR;
    498         resultlength=resultlengthneeded+1;
    499         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    500         unum_toPattern(pattern, FALSE, result, resultlength, &status);
    501     }
    502     if(U_FAILURE(status))
    503     {
    504         log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
    505     }
    506     else
    507     {
    508         if(u_strcmp(result, temp1)!=0)
    509             log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
    510         else
    511             log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
    512 free(result);
    513     }
    514 
    515     /*Testing unum_getSymbols() and unum_setSymbols()*/
    516     log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
    517     /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
    518     resultlength=0;
    519     resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status);
    520     if(status==U_BUFFER_OVERFLOW_ERROR)
    521     {
    522         status=U_ZERO_ERROR;
    523         resultlength=resultlengthneeded+1;
    524         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    525         unum_toPattern(cur_def, FALSE, result, resultlength, &status);
    526     }
    527     if(U_FAILURE(status))
    528     {
    529         log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
    530     }
    531 
    532     status=U_ZERO_ERROR;
    533     cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status);
    534     if(U_FAILURE(status))
    535     {
    536         log_err("error in unum_openPattern(): %s\n", myErrorName(status));
    537     }
    538 
    539 free(result);
    540 
    541     /*getting the symbols of cur_def */
    542     /*set the symbols of cur_frpattern to cur_def */
    543     for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
    544         status=U_ZERO_ERROR;
    545         unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
    546         unum_setSymbol(cur_frpattern, symType, temp1, -1, &status);
    547         if(U_FAILURE(status))
    548         {
    549             log_err("Error in get/set symbols: %s\n", myErrorName(status));
    550         }
    551     }
    552 
    553     /*format to check the result */
    554     resultlength=0;
    555     resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
    556     if(status==U_BUFFER_OVERFLOW_ERROR)
    557     {
    558         status=U_ZERO_ERROR;
    559         resultlength=resultlengthneeded+1;
    560         result=(UChar*)malloc(sizeof(UChar) * resultlength);
    561         unum_format(cur_def, l, result, resultlength, &pos1, &status);
    562     }
    563     if(U_FAILURE(status))
    564     {
    565         log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
    566     }
    567 
    568     if(U_FAILURE(status)){
    569         log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status));
    570     }
    571     unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL);
    572 
    573     for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
    574         status=U_ZERO_ERROR;
    575         unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
    576         unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status);
    577         if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0)
    578         {
    579             log_err("Fail: error in getting symbols\n");
    580         }
    581         else
    582             log_verbose("Pass: get and set symbols successful\n");
    583     }
    584 
    585     /*format and check with the previous result */
    586 
    587     resultlength=0;
    588     resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status);
    589     if(status==U_BUFFER_OVERFLOW_ERROR)
    590     {
    591         status=U_ZERO_ERROR;
    592         resultlength=resultlengthneeded+1;
    593         unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status);
    594     }
    595     if(U_FAILURE(status))
    596     {
    597         log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
    598     }
    599     /* TODO:
    600      * This test fails because we have not called unum_applyPattern().
    601      * Currently, such an applyPattern() does not exist on the C API, and
    602      * we have jitterbug 411 for it.
    603      * Since it is close to the 1.5 release, I (markus) am disabling this test just
    604      * for this release (I added the test itself only last week).
    605      * For the next release, we need to fix this.
    606      * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
    607      */
    608     if(u_strcmp(result, temp1) != 0) {
    609         log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1);
    610     }
    611 
    612 
    613     /*----------- */
    614 
    615 free(result);
    616 
    617     /* Testing unum_get/setSymbol() */
    618     for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
    619         symbol[0] = (UChar)(0x41 + i);
    620         symbol[1] = (UChar)(0x61 + i);
    621         unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status);
    622         if(U_FAILURE(status)) {
    623             log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status));
    624             return;
    625         }
    626     }
    627     for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
    628         resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
    629         if(U_FAILURE(status)) {
    630             log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status));
    631             return;
    632         }
    633         if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) {
    634             log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i);
    635         }
    636     }
    637     /*try getting from a bogus symbol*/
    638     unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
    639     if(U_SUCCESS(status)){
    640         log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
    641     }
    642     if(U_FAILURE(status)){
    643         if(status != U_ILLEGAL_ARGUMENT_ERROR){
    644             log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status));
    645         }
    646     }
    647     status=U_ZERO_ERROR;
    648 
    649     /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
    650     log_verbose("\nTesting getting and setting text attributes\n");
    651     resultlength=5;
    652     unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
    653     if(U_FAILURE(status))
    654     {
    655         log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
    656     }
    657     unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
    658     if(U_FAILURE(status))
    659     {
    660         log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
    661     }
    662     unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status);
    663     if(U_FAILURE(status))
    664     {
    665         log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
    666     }
    667     if(u_strcmp(suffix,temp)!=0)
    668         log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
    669     else
    670         log_verbose("Pass: setting and getting suffix works fine\n");
    671     /*set it back to normal */
    672     u_uastrcpy(temp,"$");
    673     unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
    674 
    675     /*checking some more text setter conditions */
    676     u_uastrcpy(prefix, "+");
    677     unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status);
    678     if(U_FAILURE(status))
    679     {
    680         log_err("error in setting the text attributes : %s\n", myErrorName(status));
    681     }
    682     unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status);
    683     if(U_FAILURE(status))
    684     {
    685         log_err("error in getting the text attributes : %s\n", myErrorName(status));
    686     }
    687 
    688     if(u_strcmp(prefix, temp)!=0)
    689         log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
    690     else
    691         log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
    692 
    693     u_uastrcpy(prefix, "+");
    694     unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status);
    695     if(U_FAILURE(status))
    696     {
    697         log_err("error in setting the text attributes : %s\n", myErrorName(status));
    698     }
    699     unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status);
    700     if(U_FAILURE(status))
    701     {
    702         log_err("error in getting the text attributes : %s\n", myErrorName(status));
    703     }
    704     if(u_strcmp(prefix, temp)!=0)
    705         log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
    706     else
    707         log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
    708 
    709     u_uastrcpy(suffix, "+");
    710     unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
    711     if(U_FAILURE(status))
    712     {
    713         log_err("error in setting the text attributes: %s\n", myErrorName(status));
    714     }
    715 
    716     unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
    717     if(U_FAILURE(status))
    718     {
    719         log_err("error in getting the text attributes : %s\n", myErrorName(status));
    720     }
    721     if(u_strcmp(suffix, temp)!=0)
    722         log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
    723     else
    724         log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
    725 
    726     u_uastrcpy(suffix, "++");
    727     unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
    728     if(U_FAILURE(status))
    729     {
    730         log_err("error in setting the text attributes: %s\n", myErrorName(status));
    731     }
    732 
    733     unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status);
    734     if(U_FAILURE(status))
    735     {
    736         log_err("error in getting the text attributes : %s\n", myErrorName(status));
    737     }
    738     if(u_strcmp(suffix, temp)!=0)
    739         log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
    740     else
    741         log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
    742 
    743     /*Testing unum_getAttribute and  unum_setAttribute() */
    744     log_verbose("\nTesting get and set Attributes\n");
    745     attr=UNUM_GROUPING_SIZE;
    746     newvalue=unum_getAttribute(def, attr);
    747     newvalue=2;
    748     unum_setAttribute(def, attr, newvalue);
    749     if(unum_getAttribute(def,attr)!=2)
    750         log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
    751     else
    752         log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
    753 
    754     attr=UNUM_MULTIPLIER;
    755     newvalue=unum_getAttribute(def, attr);
    756     newvalue=8;
    757     unum_setAttribute(def, attr, newvalue);
    758     if(unum_getAttribute(def,attr) != 8)
    759         log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
    760     else
    761         log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
    762 
    763     attr=UNUM_SECONDARY_GROUPING_SIZE;
    764     newvalue=unum_getAttribute(def, attr);
    765     newvalue=2;
    766     unum_setAttribute(def, attr, newvalue);
    767     if(unum_getAttribute(def,attr) != 2)
    768         log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
    769     else
    770         log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
    771 
    772     /*testing set and get Attributes extensively */
    773     log_verbose("\nTesting get and set attributes extensively\n");
    774     for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) )
    775     {
    776         newvalue=unum_getAttribute(fr, attr);
    777         unum_setAttribute(def, attr, newvalue);
    778         if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr))
    779             log_err("error in setting and getting attributes\n");
    780         else
    781             log_verbose("Pass: attributes set and retrieved successfully\n");
    782     }
    783 
    784     /*testing spellout format to make sure we can use it successfully.*/
    785     log_verbose("\nTesting spellout format\n");
    786     if (spellout_def)
    787     {
    788         static const int32_t values[] = { 0, -5, 105, 1005, 105050 };
    789         for (i = 0; i < UPRV_LENGTHOF(values); ++i) {
    790             UChar buffer[128];
    791             int32_t len;
    792             int32_t value = values[i];
    793             status = U_ZERO_ERROR;
    794             len = unum_format(spellout_def, value, buffer, UPRV_LENGTHOF(buffer), NULL, &status);
    795             if(U_FAILURE(status)) {
    796                 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
    797             } else {
    798                 int32_t pp = 0;
    799                 int32_t parseResult;
    800                 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
    801                 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
    802 
    803                 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status);
    804                 if (U_FAILURE(status)) {
    805                     log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
    806                 } else if (parseResult != value) {
    807                     log_err("unum_format result %d != value %d\n", parseResult, value);
    808                 }
    809             }
    810         }
    811     }
    812     else {
    813         log_err("Spellout format is unavailable\n");
    814     }
    815 
    816     {    /* Test for ticket #7079 */
    817         UNumberFormat* dec_en;
    818         UChar groupingSep[] = { 0 };
    819         UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
    820         double parseResult = 0.0;
    821 
    822         status=U_ZERO_ERROR;
    823         dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
    824         unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0);
    825         unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status);
    826         parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status);
    827         /* Without the fix in #7079, the above call will hang */
    828         if ( U_FAILURE(status) || parseResult != 12.0 ) {
    829             log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
    830                     myErrorName(status), parseResult);
    831         } else {
    832             log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
    833         }
    834         unum_close(dec_en);
    835     }
    836 
    837     {   /* Test parse & format of big decimals.  Use a number with too many digits to fit in a double,
    838                                          to verify that it is taking the pure decimal path. */
    839         UNumberFormat *fmt;
    840         const char *bdpattern = "#,##0.#########";
    841         const char *numInitial     = "12345678900987654321.1234567896";
    842         const char *numFormatted  = "12,345,678,900,987,654,321.12345679";
    843         const char *parseExpected = "12345678900987654321.12345679";
    844         int32_t resultSize    = 0;
    845         int32_t parsePos      = 0;     /* Output parameter for Parse operations. */
    846         #define DESTCAPACITY 100
    847         UChar dest[DESTCAPACITY];
    848         char  desta[DESTCAPACITY];
    849         UFieldPosition fieldPos = {0};
    850 
    851         /* Format */
    852 
    853         status = U_ZERO_ERROR;
    854         u_uastrcpy(dest, bdpattern);
    855         fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status);
    856         if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    857 
    858         resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status);
    859         if (U_FAILURE(status)) {
    860             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    861         }
    862         u_austrncpy(desta, dest, DESTCAPACITY);
    863         if (strcmp(numFormatted, desta) != 0) {
    864             log_err("File %s, Line %d, (expected, acutal) =  (\"%s\", \"%s\")\n",
    865                     __FILE__, __LINE__, numFormatted, desta);
    866         }
    867         if (strlen(numFormatted) != resultSize) {
    868             log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
    869                      __FILE__, __LINE__, strlen(numFormatted), resultSize);
    870         }
    871 
    872         /* Format with a FieldPosition parameter */
    873 
    874         fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
    875         resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status);
    876         if (U_FAILURE(status)) {
    877             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    878         }
    879         u_austrncpy(desta, dest, DESTCAPACITY);
    880         if (strcmp(numFormatted, desta) != 0) {
    881             log_err("File %s, Line %d, (expected, acutal) =  (\"%s\", \"%s\")\n",
    882                     __FILE__, __LINE__, numFormatted, desta);
    883         }
    884         if (fieldPos.beginIndex != 26) {  /* index of "." in formatted number */
    885             log_err("File %s, Line %d, (expected, acutal) =  (%d, %d)\n",
    886                     __FILE__, __LINE__, 0, fieldPos.beginIndex);
    887         }
    888         if (fieldPos.endIndex != 27) {
    889             log_err("File %s, Line %d, (expected, acutal) =  (%d, %d)\n",
    890                     __FILE__, __LINE__, 0, fieldPos.endIndex);
    891         }
    892 
    893         /* Parse */
    894 
    895         status = U_ZERO_ERROR;
    896         u_uastrcpy(dest, numFormatted);   /* Parse the expected output of the formatting test */
    897         resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status);
    898         if (U_FAILURE(status)) {
    899             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    900         }
    901         if (strcmp(parseExpected, desta) != 0) {
    902             log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
    903                     __FILE__, __LINE__, parseExpected, desta);
    904         }
    905         if (strlen(parseExpected) != resultSize) {
    906             log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
    907                     __FILE__, __LINE__, strlen(parseExpected), resultSize);
    908         }
    909 
    910         /* Parse with a parsePos parameter */
    911 
    912         status = U_ZERO_ERROR;
    913         u_uastrcpy(dest, numFormatted);   /* Parse the expected output of the formatting test */
    914         parsePos = 3;                 /*      12,345,678,900,987,654,321.12345679         */
    915                                       /* start parsing at the the third char              */
    916         resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status);
    917         if (U_FAILURE(status)) {
    918             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    919         }
    920         if (strcmp(parseExpected+2, desta) != 0) {   /*  "345678900987654321.12345679" */
    921             log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
    922                     __FILE__, __LINE__, parseExpected+2, desta);
    923         }
    924         if (strlen(numFormatted) != parsePos) {
    925             log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
    926                     __FILE__, __LINE__, strlen(parseExpected), parsePos);
    927         }
    928 
    929         unum_close(fmt);
    930     }
    931 
    932     status = U_ZERO_ERROR;
    933     /* Test invalid symbol argument */
    934     {
    935         int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1;
    936         int32_t badsymbolSmall = -1;
    937         UChar value[10];
    938         int32_t valueLength = 10;
    939         UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
    940         if (U_FAILURE(status)) {
    941             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
    942         } else {
    943             unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status);
    944             if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
    945 
    946             status = U_ZERO_ERROR;
    947             unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status);
    948             if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
    949 
    950             status = U_ZERO_ERROR;
    951             unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status);
    952             if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
    953 
    954             status = U_ZERO_ERROR;
    955             unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status);
    956             if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
    957 
    958             unum_close(fmt);
    959         }
    960     }
    961 
    962 
    963     /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
    964     unum_close(def);
    965     unum_close(fr);
    966     unum_close(cur_def);
    967     unum_close(cur_fr);
    968     unum_close(per_def);
    969     unum_close(per_fr);
    970     unum_close(spellout_def);
    971     unum_close(pattern);
    972     unum_close(cur_frpattern);
    973     unum_close(myclone);
    974 
    975 }
    976 
    977 static void TestParseZero(void)
    978 {
    979     UErrorCode errorCode = U_ZERO_ERROR;
    980     UChar input[] = {0x30, 0};   /*  Input text is decimal '0' */
    981     UChar pat[] = {0x0023,0x003b,0x0023,0}; /*  {'#', ';', '#', 0}; */
    982     double  dbl;
    983 
    984 #if 0
    985     UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode);
    986 #else
    987     UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode);
    988 #endif
    989 
    990     dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode );
    991     if (U_FAILURE(errorCode)) {
    992         log_data_err("Result - %s\n", u_errorName(errorCode));
    993     } else {
    994         log_verbose("Double: %f\n", dbl);
    995     }
    996     unum_close(unum);
    997 }
    998 
    999 static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
   1000 static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */
   1001 static const UChar dollarsUS4Sym[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
   1002 static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
   1003 static const UChar pounds3Sym[]  = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
   1004 static const UChar pounds5Sym[]  = { 0xA3,0x35,0 }; /* [POUND]5 */
   1005 static const UChar pounds7Sym[]  = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
   1006 static const UChar euros4Sym[]   = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
   1007 static const UChar euros6Sym[]   = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
   1008 static const UChar euros8Sym[]   = { 0x20AC,0x38,0 }; /* [EURO]8 */
   1009 static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
   1010 static const UChar pounds5PluEn[]  = { 0x35,0x20,0x42,0x72,0x69,0x74,0x69,0x73,0x68,0x20,0x70,0x6F,0x75,0x6E,0x64,0x73,0x20,0x73,0x74,0x65,0x72,0x6C,0x69,0x6E,0x67,0 }; /* 5 British pounds sterling */
   1011 static const UChar euros8PluEn[]   = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
   1012 static const UChar euros6PluFr[]   = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
   1013 
   1014 typedef struct {
   1015     const char *  locale;
   1016     const char *  descrip;
   1017     const UChar * currStr;
   1018     const UChar * plurStr;
   1019     UErrorCode    parsDoubExpectErr;
   1020     int32_t       parsDoubExpectPos;
   1021     double        parsDoubExpectVal;
   1022     UErrorCode    parsCurrExpectErr;
   1023     int32_t       parsCurrExpectPos;
   1024     double        parsCurrExpectVal;
   1025     const char *  parsCurrExpectCurr;
   1026 } ParseCurrencyItem;
   1027 
   1028 static const ParseCurrencyItem parseCurrencyItems[] = {
   1029     { "en_US", "dollars2", dollars2Sym, NULL,          U_ZERO_ERROR,  5, 2.0, U_ZERO_ERROR,  5, 2.0, "USD" },
   1030     { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR,  2, 4.0, U_ZERO_ERROR,  2, 4.0, "USD" },
   1031     { "en_US", "dollars9", dollars9Sym, NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
   1032     { "en_US", "pounds3",  pounds3Sym,  NULL,          U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
   1033     { "en_US", "pounds5",  pounds5Sym,  pounds5PluEn,  U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
   1034     { "en_US", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
   1035     { "en_US", "euros8",   euros8Sym,   euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
   1036 
   1037     { "en_GB", "pounds3",  pounds3Sym,  NULL,          U_ZERO_ERROR,  5, 3.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
   1038     { "en_GB", "pounds5",  pounds5Sym,  pounds5PluEn,  U_ZERO_ERROR,  2, 5.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
   1039     { "en_GB", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
   1040     { "en_GB", "euros4",   euros4Sym,   NULL,          U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, ""    },
   1041     { "en_GB", "euros6",   euros6Sym,   NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
   1042     { "en_GB", "euros8",   euros8Sym,     euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
   1043     { "en_GB", "dollars4", dollarsUS4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  4, 4.0, "USD" },
   1044 
   1045     { "fr_FR", "euros4",   euros4Sym,   NULL,          U_ZERO_ERROR,  6, 4.0, U_ZERO_ERROR,  6, 4.0, "EUR" },
   1046     { "fr_FR", "euros6",   euros6Sym,   euros6PluFr,   U_ZERO_ERROR,  3, 6.0, U_ZERO_ERROR,  3, 6.0, "EUR" },
   1047     { "fr_FR", "euros8",   euros8Sym,   NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
   1048     { "fr_FR", "dollars2", dollars2Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
   1049     { "fr_FR", "dollars4", dollars4Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
   1050 
   1051     { NULL,    NULL,       NULL,        NULL,          0,             0, 0.0, 0,             0, 0.0, NULL  }
   1052 };
   1053 
   1054 static void TestParseCurrency()
   1055 {
   1056     const ParseCurrencyItem * itemPtr;
   1057     for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) {
   1058         UNumberFormat* unum;
   1059         UErrorCode status;
   1060         double parseVal;
   1061         int32_t parsePos;
   1062         UChar parseCurr[4];
   1063         char parseCurrB[4];
   1064 
   1065         status = U_ZERO_ERROR;
   1066         unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
   1067         if (U_SUCCESS(status)) {
   1068             const UChar * currStr = itemPtr->currStr;
   1069             int32_t currExpectPos = itemPtr->parsCurrExpectPos;
   1070             status = U_ZERO_ERROR;
   1071             parsePos = 0;
   1072             parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status);
   1073             if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
   1074                 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
   1075                         itemPtr->locale, itemPtr->descrip,
   1076                         u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
   1077                         u_errorName(status), parsePos, parseVal );
   1078             }
   1079             status = U_ZERO_ERROR;
   1080             parsePos = 0;
   1081             parseCurr[0] = 0;
   1082             parseVal = unum_parseDoubleCurrency(unum, currStr, -1, &parsePos, parseCurr, &status);
   1083             u_austrncpy(parseCurrB, parseCurr, 4);
   1084             if (status != itemPtr->parsCurrExpectErr || parsePos != currExpectPos || parseVal != itemPtr->parsCurrExpectVal ||
   1085                     strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
   1086                 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
   1087                         itemPtr->locale, itemPtr->descrip,
   1088                         u_errorName(itemPtr->parsCurrExpectErr), currExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
   1089                         u_errorName(status), parsePos, parseVal, parseCurrB );
   1090             }
   1091             unum_close(unum);
   1092         } else {
   1093             log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
   1094         }
   1095 
   1096         if (itemPtr->plurStr != NULL) {
   1097             status = U_ZERO_ERROR;
   1098             unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status);
   1099             if (U_SUCCESS(status)) {
   1100                 status = U_ZERO_ERROR;
   1101                 parsePos = 0;
   1102                 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
   1103                 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
   1104                     log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
   1105                             itemPtr->locale, itemPtr->descrip,
   1106                             u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
   1107                             u_errorName(status), parseVal );
   1108                 }
   1109                 status = U_ZERO_ERROR;
   1110                 parsePos = 0;
   1111                 parseCurr[0] = 0;
   1112                 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status);
   1113                 u_austrncpy(parseCurrB, parseCurr, 4);
   1114                 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal ||
   1115                         strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
   1116                     log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
   1117                             itemPtr->locale, itemPtr->descrip,
   1118                             u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
   1119                             u_errorName(status), parseVal, parseCurrB );
   1120                 }
   1121                 unum_close(unum);
   1122             } else {
   1123                 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
   1124             }
   1125         }
   1126     }
   1127 }
   1128 
   1129 typedef struct {
   1130     const char *  testname;
   1131     const char *  locale;
   1132     const UChar * source;
   1133     int32_t       startPos;
   1134     int32_t       value;
   1135     int32_t       endPos;
   1136     UErrorCode    status;
   1137 } SpelloutParseTest;
   1138 
   1139 static const UChar ustr_en0[]   = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
   1140 static const UChar ustr_123[]   = {0x31, 0x32, 0x33, 0};       /* 123 */
   1141 static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
   1142                                    0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
   1143                                    0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
   1144 static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
   1145                                    0x74, 0x72, 0x6f, 0x69, 0x73, 0};       /* cent vingt-trois */
   1146 static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0};     /* kanji 100(+)2(*)10(+)3 */
   1147 
   1148 static const SpelloutParseTest spelloutParseTests[] = {
   1149     /* name    loc   src       start val  end status */
   1150     { "en0",   "en", ustr_en0,    0,   0,  4, U_ZERO_ERROR },
   1151     { "en0",   "en", ustr_en0,    2,   0,  2, U_PARSE_ERROR },
   1152     { "en0",   "ja", ustr_en0,    0,   0,  0, U_PARSE_ERROR },
   1153     { "123",   "en", ustr_123,    0, 123,  3, U_ZERO_ERROR },
   1154     { "en123", "en", ustr_en123,  0, 123, 24, U_ZERO_ERROR },
   1155     { "en123", "en", ustr_en123, 12,  23, 24, U_ZERO_ERROR },
   1156     { "en123", "fr", ustr_en123, 16,   0, 16, U_PARSE_ERROR },
   1157     { "fr123", "fr", ustr_fr123,  0, 123, 16, U_ZERO_ERROR },
   1158     { "fr123", "fr", ustr_fr123,  5,  23, 16, U_ZERO_ERROR },
   1159     { "fr123", "en", ustr_fr123,  0,   0,  0, U_PARSE_ERROR },
   1160     { "ja123", "ja", ustr_ja123,  0, 123,  4, U_ZERO_ERROR },
   1161     { "ja123", "ja", ustr_ja123,  1,  23,  4, U_ZERO_ERROR },
   1162     { "ja123", "fr", ustr_ja123,  0,   0,  0, U_PARSE_ERROR },
   1163     { NULL,    NULL, NULL,        0,   0,  0, 0 } /* terminator */
   1164 };
   1165 
   1166 static void TestSpelloutNumberParse()
   1167 {
   1168     const SpelloutParseTest * testPtr;
   1169     for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
   1170         UErrorCode status = U_ZERO_ERROR;
   1171         int32_t value, position = testPtr->startPos;
   1172         UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
   1173         if (U_FAILURE(status)) {
   1174             log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
   1175             continue;
   1176         }
   1177         status = U_ZERO_ERROR;
   1178         value = unum_parse(nf, testPtr->source, -1, &position, &status);
   1179         if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
   1180             log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
   1181                     testPtr->locale, testPtr->testname, testPtr->startPos,
   1182                     testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
   1183                     value, position, myErrorName(status) );
   1184         }
   1185         unum_close(nf);
   1186     }
   1187 }
   1188 
   1189 static void TestSignificantDigits()
   1190 {
   1191     UChar temp[128];
   1192     int32_t resultlengthneeded;
   1193     int32_t resultlength;
   1194     UErrorCode status = U_ZERO_ERROR;
   1195     UChar *result = NULL;
   1196     UNumberFormat* fmt;
   1197     double d = 123456.789;
   1198 
   1199     u_uastrcpy(temp, "###0.0#");
   1200     fmt=unum_open(UNUM_IGNORE, temp, -1, NULL, NULL,&status);
   1201     if (U_FAILURE(status)) {
   1202         log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
   1203         return;
   1204     }
   1205     unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
   1206     unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6);
   1207 
   1208     u_uastrcpy(temp, "123457");
   1209     resultlength=0;
   1210     resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status);
   1211     if(status==U_BUFFER_OVERFLOW_ERROR)
   1212     {
   1213         status=U_ZERO_ERROR;
   1214         resultlength=resultlengthneeded+1;
   1215         result=(UChar*)malloc(sizeof(UChar) * resultlength);
   1216         unum_formatDouble(fmt, d, result, resultlength, NULL, &status);
   1217     }
   1218     if(U_FAILURE(status))
   1219     {
   1220         log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
   1221         return;
   1222     }
   1223     if(u_strcmp(result, temp)==0)
   1224         log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
   1225     else
   1226         log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
   1227     free(result);
   1228     unum_close(fmt);
   1229 }
   1230 
   1231 static void TestSigDigRounding()
   1232 {
   1233     UErrorCode status = U_ZERO_ERROR;
   1234     UChar expected[128];
   1235     UChar result[128];
   1236     char  temp1[128];
   1237     char  temp2[128];
   1238     UNumberFormat* fmt;
   1239     double d = 123.4;
   1240 
   1241     fmt=unum_open(UNUM_DECIMAL, NULL, 0, NULL /* "en_US"*/, NULL, &status);
   1242     if (U_FAILURE(status)) {
   1243         log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
   1244         return;
   1245     }
   1246     unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE);
   1247     unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
   1248     unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2);
   1249     /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
   1250 
   1251     unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP);
   1252     unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0);
   1253 
   1254     (void)unum_formatDouble(fmt, d, result, UPRV_LENGTHOF(result), NULL, &status);
   1255     if(U_FAILURE(status))
   1256     {
   1257         log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
   1258         return;
   1259     }
   1260 
   1261     u_uastrcpy(expected, "140");
   1262     if(u_strcmp(result, expected)!=0)
   1263         log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) );
   1264 
   1265     unum_close(fmt);
   1266 }
   1267 
   1268 static void TestNumberFormatPadding()
   1269 {
   1270     UChar *result=NULL;
   1271     UChar temp1[512];
   1272 
   1273     UErrorCode status=U_ZERO_ERROR;
   1274     int32_t resultlength;
   1275     int32_t resultlengthneeded;
   1276     UNumberFormat *pattern;
   1277     double d1;
   1278     double d = -10456.37;
   1279     UFieldPosition pos1;
   1280     int32_t parsepos;
   1281 
   1282     /* create a number format using unum_openPattern(....)*/
   1283     log_verbose("\nTesting unum_openPattern() with padding\n");
   1284     u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)");
   1285     status=U_ZERO_ERROR;
   1286     pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
   1287     if(U_SUCCESS(status))
   1288     {
   1289         log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
   1290     }
   1291     else
   1292     {
   1293         unum_close(pattern);
   1294     }
   1295 
   1296 /*    u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
   1297     u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
   1298     status=U_ZERO_ERROR;
   1299     pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
   1300     if(U_FAILURE(status))
   1301     {
   1302         log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
   1303     }
   1304     else {
   1305         log_verbose("Pass: padding unum_openPattern() works fine\n");
   1306 
   1307         /*test for unum_toPattern()*/
   1308         log_verbose("\nTesting padding unum_toPattern()\n");
   1309         resultlength=0;
   1310         resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
   1311         if(status==U_BUFFER_OVERFLOW_ERROR)
   1312         {
   1313             status=U_ZERO_ERROR;
   1314             resultlength=resultlengthneeded+1;
   1315             result=(UChar*)malloc(sizeof(UChar) * resultlength);
   1316             unum_toPattern(pattern, FALSE, result, resultlength, &status);
   1317         }
   1318         if(U_FAILURE(status))
   1319         {
   1320             log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status));
   1321         }
   1322         else
   1323         {
   1324             if(u_strcmp(result, temp1)!=0)
   1325                 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
   1326             else
   1327                 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
   1328 free(result);
   1329         }
   1330 /*        u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
   1331         u_uastrcpy(temp1, "xxxxx(10,456.37)");
   1332         resultlength=0;
   1333         pos1.field = UNUM_FRACTION_FIELD;
   1334         resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status);
   1335         if(status==U_BUFFER_OVERFLOW_ERROR)
   1336         {
   1337             status=U_ZERO_ERROR;
   1338             resultlength=resultlengthneeded+1;
   1339             result=(UChar*)malloc(sizeof(UChar) * resultlength);
   1340             unum_formatDouble(pattern, d, result, resultlength, NULL, &status);
   1341         }
   1342         if(U_FAILURE(status))
   1343         {
   1344             log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status));
   1345         }
   1346         else
   1347         {
   1348             if(u_strcmp(result, temp1)==0)
   1349                 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
   1350             else
   1351                 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
   1352             if(pos1.beginIndex == 13 && pos1.endIndex == 15)
   1353                 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
   1354             else
   1355                 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
   1356                         pos1.beginIndex, pos1.endIndex);
   1357 
   1358 
   1359             /* Testing unum_parse() and unum_parseDouble() */
   1360             log_verbose("\nTesting padding unum_parseDouble()\n");
   1361             parsepos=0;
   1362             d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status);
   1363             if(U_FAILURE(status))
   1364             {
   1365                 log_err("padding parse failed. The error is : %s\n", myErrorName(status));
   1366             }
   1367 
   1368             if(d1!=d)
   1369                 log_err("Fail: Error in padding parsing\n");
   1370             else
   1371                 log_verbose("Pass: padding parsing successful\n");
   1372 free(result);
   1373         }
   1374     }
   1375 
   1376     unum_close(pattern);
   1377 }
   1378 
   1379 static UBool
   1380 withinErr(double a, double b, double err) {
   1381     return uprv_fabs(a - b) < uprv_fabs(a * err);
   1382 }
   1383 
   1384 static void TestInt64Format() {
   1385     UChar temp1[512];
   1386     UChar result[512];
   1387     UNumberFormat *fmt;
   1388     UErrorCode status = U_ZERO_ERROR;
   1389     const double doubleInt64Max = (double)U_INT64_MAX;
   1390     const double doubleInt64Min = (double)U_INT64_MIN;
   1391     const double doubleBig = 10.0 * (double)U_INT64_MAX;
   1392     int32_t val32;
   1393     int64_t val64;
   1394     double  valDouble;
   1395     int32_t parsepos;
   1396 
   1397     /* create a number format using unum_openPattern(....) */
   1398     log_verbose("\nTesting Int64Format\n");
   1399     u_uastrcpy(temp1, "#.#E0");
   1400     fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), "en_US", NULL, &status);
   1401     if(U_FAILURE(status)) {
   1402         log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
   1403     } else {
   1404         unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20);
   1405         unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status);
   1406         if (U_FAILURE(status)) {
   1407             log_err("error in unum_format(): %s\n", myErrorName(status));
   1408         } else {
   1409             log_verbose("format int64max: '%s'\n", result);
   1410             parsepos = 0;
   1411             val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
   1412             if (status != U_INVALID_FORMAT_ERROR) {
   1413                 log_err("parse didn't report error: %s\n", myErrorName(status));
   1414             } else if (val32 != INT32_MAX) {
   1415                 log_err("parse didn't pin return value, got: %d\n", val32);
   1416             }
   1417 
   1418             status = U_ZERO_ERROR;
   1419             parsepos = 0;
   1420             val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
   1421             if (U_FAILURE(status)) {
   1422                 log_err("parseInt64 returned error: %s\n", myErrorName(status));
   1423             } else if (val64 != U_INT64_MAX) {
   1424                 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
   1425             }
   1426 
   1427             status = U_ZERO_ERROR;
   1428             parsepos = 0;
   1429             valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
   1430             if (U_FAILURE(status)) {
   1431                 log_err("parseDouble returned error: %s\n", myErrorName(status));
   1432             } else if (valDouble != doubleInt64Max) {
   1433                 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
   1434             }
   1435         }
   1436 
   1437         unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status);
   1438         if (U_FAILURE(status)) {
   1439             log_err("error in unum_format(): %s\n", myErrorName(status));
   1440         } else {
   1441             log_verbose("format int64min: '%s'\n", result);
   1442             parsepos = 0;
   1443             val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
   1444             if (status != U_INVALID_FORMAT_ERROR) {
   1445                 log_err("parse didn't report error: %s\n", myErrorName(status));
   1446             } else if (val32 != INT32_MIN) {
   1447                 log_err("parse didn't pin return value, got: %d\n", val32);
   1448             }
   1449 
   1450             status = U_ZERO_ERROR;
   1451             parsepos = 0;
   1452             val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
   1453             if (U_FAILURE(status)) {
   1454                 log_err("parseInt64 returned error: %s\n", myErrorName(status));
   1455             } else if (val64 != U_INT64_MIN) {
   1456                 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
   1457             }
   1458 
   1459             status = U_ZERO_ERROR;
   1460             parsepos = 0;
   1461             valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
   1462             if (U_FAILURE(status)) {
   1463                 log_err("parseDouble returned error: %s\n", myErrorName(status));
   1464             } else if (valDouble != doubleInt64Min) {
   1465                 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
   1466             }
   1467         }
   1468 
   1469         unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status);
   1470         if (U_FAILURE(status)) {
   1471             log_err("error in unum_format(): %s\n", myErrorName(status));
   1472         } else {
   1473             log_verbose("format doubleBig: '%s'\n", result);
   1474             parsepos = 0;
   1475             val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
   1476             if (status != U_INVALID_FORMAT_ERROR) {
   1477                 log_err("parse didn't report error: %s\n", myErrorName(status));
   1478             } else if (val32 != INT32_MAX) {
   1479                 log_err("parse didn't pin return value, got: %d\n", val32);
   1480             }
   1481 
   1482             status = U_ZERO_ERROR;
   1483             parsepos = 0;
   1484             val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
   1485             if (status != U_INVALID_FORMAT_ERROR) {
   1486                 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status));
   1487             } else if (val64 != U_INT64_MAX) {
   1488                 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
   1489             }
   1490 
   1491             status = U_ZERO_ERROR;
   1492             parsepos = 0;
   1493             valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
   1494             if (U_FAILURE(status)) {
   1495                 log_err("parseDouble returned error: %s\n", myErrorName(status));
   1496             } else if (!withinErr(valDouble, doubleBig, 1e-15)) {
   1497                 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
   1498             }
   1499         }
   1500 
   1501         u_uastrcpy(result, "5.06e-27");
   1502         parsepos = 0;
   1503         valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
   1504         if (U_FAILURE(status)) {
   1505             log_err("parseDouble() returned error: %s\n", myErrorName(status));
   1506         } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) {
   1507             log_err("parseDouble() returned incorrect value, got: %g\n", valDouble);
   1508         }
   1509     }
   1510     unum_close(fmt);
   1511 }
   1512 
   1513 
   1514 static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
   1515     char temp[512];
   1516     UChar buffer[512];
   1517     int32_t BUFSIZE = UPRV_LENGTHOF(buffer);
   1518     double vals[] = {
   1519         -.2, 0, .2, 5.5, 15.2, 250, 123456789
   1520     };
   1521     int i;
   1522 
   1523     for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
   1524         UErrorCode status = U_ZERO_ERROR;
   1525         unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
   1526         if (U_FAILURE(status)) {
   1527             log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
   1528         } else {
   1529             u_austrcpy(temp, buffer);
   1530             log_verbose("formatting %g returned '%s'\n", vals[i], temp);
   1531         }
   1532     }
   1533 
   1534     /* check APIs now */
   1535     {
   1536         UErrorCode status = U_ZERO_ERROR;
   1537         UParseError perr;
   1538         u_uastrcpy(buffer, "#,##0.0#");
   1539         unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status);
   1540         if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
   1541             log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status));
   1542         }
   1543     }
   1544 
   1545     {
   1546         int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
   1547         log_verbose("lenient: 0x%x\n", isLenient);
   1548         if (isLenient != FALSE) {
   1549             log_err("didn't expect lenient value: %d\n", isLenient);
   1550         }
   1551 
   1552         unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE);
   1553         isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
   1554         if (isLenient != TRUE) {
   1555             log_err("didn't expect lenient value after set: %d\n", isLenient);
   1556         }
   1557     }
   1558 
   1559     {
   1560         double val2;
   1561         double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE);
   1562         if (val != -1) {
   1563             log_err("didn't expect double attribute\n");
   1564         }
   1565         val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
   1566         if ((val == -1) == isDecimal) {
   1567             log_err("didn't expect -1 rounding increment\n");
   1568         }
   1569         unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5);
   1570         val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
   1571         if (isDecimal && (val2 - val != .5)) {
   1572             log_err("set rounding increment had no effect on decimal format");
   1573         }
   1574     }
   1575 
   1576     {
   1577         UErrorCode status = U_ZERO_ERROR;
   1578         int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
   1579         if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
   1580             log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status));
   1581         }
   1582         if (U_SUCCESS(status)) {
   1583             u_austrcpy(temp, buffer);
   1584             log_verbose("default ruleset: '%s'\n", temp);
   1585         }
   1586 
   1587         status = U_ZERO_ERROR;
   1588         len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status);
   1589         if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
   1590             log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status));
   1591         }
   1592         if (U_SUCCESS(status)) {
   1593             u_austrcpy(temp, buffer);
   1594             log_verbose("public rulesets: '%s'\n", temp);
   1595 
   1596             /* set the default ruleset to the first one found, and retry */
   1597 
   1598             if (len > 0) {
   1599                 for (i = 0; i < len && temp[i] != ';'; ++i){};
   1600                 if (i < len) {
   1601                     buffer[i] = 0;
   1602                     unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status);
   1603                     if (U_FAILURE(status)) {
   1604                         log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status));
   1605                     } else {
   1606                         int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
   1607                         if (U_FAILURE(status)) {
   1608                             log_err("could not fetch default ruleset: '%s'\n", u_errorName(status));
   1609                         } else if (len2 != i) {
   1610                             u_austrcpy(temp, buffer);
   1611                             log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp);
   1612                         } else {
   1613                             for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
   1614                                 status = U_ZERO_ERROR;
   1615                                 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
   1616                                 if (U_FAILURE(status)) {
   1617                                     log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
   1618                                 } else {
   1619                                     u_austrcpy(temp, buffer);
   1620                                     log_verbose("formatting %g returned '%s'\n", vals[i], temp);
   1621                                 }
   1622                             }
   1623                         }
   1624                     }
   1625                 }
   1626             }
   1627         }
   1628     }
   1629 
   1630     {
   1631         UErrorCode status = U_ZERO_ERROR;
   1632         unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status);
   1633         if (U_SUCCESS(status)) {
   1634             u_austrcpy(temp, buffer);
   1635             log_verbose("pattern: '%s'\n", temp);
   1636         } else if (status != U_BUFFER_OVERFLOW_ERROR) {
   1637             log_err("toPattern failed unexpectedly: %s\n", u_errorName(status));
   1638         } else {
   1639             log_verbose("pattern too long to display\n");
   1640         }
   1641     }
   1642 
   1643     {
   1644         UErrorCode status = U_ZERO_ERROR;
   1645         int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status);
   1646         if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
   1647             log_err("unexpected error getting symbol: '%s'\n", u_errorName(status));
   1648         }
   1649 
   1650         unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status);
   1651         if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
   1652             log_err("unexpected error setting symbol: '%s'\n", u_errorName(status));
   1653         }
   1654     }
   1655 }
   1656 
   1657 static void TestNonExistentCurrency() {
   1658     UNumberFormat *format;
   1659     UErrorCode status = U_ZERO_ERROR;
   1660     UChar currencySymbol[8];
   1661     static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
   1662 
   1663     /* Get a non-existent currency and make sure it returns the correct currency code. */
   1664     format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status);
   1665     if (format == NULL || U_FAILURE(status)) {
   1666         log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status));
   1667     }
   1668     else {
   1669         unum_getSymbol(format,
   1670                 UNUM_CURRENCY_SYMBOL,
   1671                 currencySymbol,
   1672                 UPRV_LENGTHOF(currencySymbol),
   1673                 &status);
   1674         if (u_strcmp(currencySymbol, QQQ) != 0) {
   1675             log_err("unum_open set the currency to QQQ\n");
   1676         }
   1677     }
   1678     unum_close(format);
   1679 }
   1680 
   1681 static void TestRBNFFormat() {
   1682     UErrorCode status;
   1683     UParseError perr;
   1684     UChar pat[1024];
   1685     UChar tempUChars[512];
   1686     UNumberFormat *formats[5];
   1687     int COUNT = UPRV_LENGTHOF(formats);
   1688     int i;
   1689 
   1690     for (i = 0; i < COUNT; ++i) {
   1691         formats[i] = 0;
   1692     }
   1693 
   1694     /* instantiation */
   1695     status = U_ZERO_ERROR;
   1696     u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)");
   1697     formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status);
   1698     if (U_FAILURE(status)) {
   1699         log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
   1700         return;
   1701     }
   1702 
   1703     status = U_ZERO_ERROR;
   1704     formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status);
   1705     if (U_FAILURE(status)) {
   1706         log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
   1707         return;
   1708     }
   1709 
   1710     status = U_ZERO_ERROR;
   1711     formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status);
   1712     if (U_FAILURE(status)) {
   1713         log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
   1714         return;
   1715     }
   1716 
   1717     status = U_ZERO_ERROR;
   1718     formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status);
   1719     if (U_FAILURE(status)) {
   1720         log_err_status(status, "unable to open duration %s\n", u_errorName(status));
   1721         return;
   1722     }
   1723 
   1724     status = U_ZERO_ERROR;
   1725     u_uastrcpy(pat,
   1726         "%standard:\n"
   1727         "-x: minus >>;\n"
   1728         "x.x: << point >>;\n"
   1729         "zero; one; two; three; four; five; six; seven; eight; nine;\n"
   1730         "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
   1731         "seventeen; eighteen; nineteen;\n"
   1732         "20: twenty[->>];\n"
   1733         "30: thirty[->>];\n"
   1734         "40: forty[->>];\n"
   1735         "50: fifty[->>];\n"
   1736         "60: sixty[->>];\n"
   1737         "70: seventy[->>];\n"
   1738         "80: eighty[->>];\n"
   1739         "90: ninety[->>];\n"
   1740         "100: =#,##0=;\n");
   1741     u_uastrcpy(tempUChars,
   1742         "%simple:\n"
   1743         "=%standard=;\n"
   1744         "20: twenty[ and change];\n"
   1745         "30: thirty[ and change];\n"
   1746         "40: forty[ and change];\n"
   1747         "50: fifty[ and change];\n"
   1748         "60: sixty[ and change];\n"
   1749         "70: seventy[ and change];\n"
   1750         "80: eighty[ and change];\n"
   1751         "90: ninety[ and change];\n"
   1752         "100: =#,##0=;\n"
   1753         "%bogus:\n"
   1754         "0.x: tiny;\n"
   1755         "x.x: << point something;\n"
   1756         "=%standard=;\n"
   1757         "20: some reasonable number;\n"
   1758         "100: some substantial number;\n"
   1759         "100,000,000: some huge number;\n");
   1760     /* This is to get around some compiler warnings about char * string length. */
   1761     u_strcat(pat, tempUChars);
   1762     formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status);
   1763     if (U_FAILURE(status)) {
   1764         log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
   1765     }
   1766     if (U_FAILURE(status)) {
   1767         log_err_status(status, "Something failed with %s\n", u_errorName(status));
   1768         return;
   1769     }
   1770 
   1771     for (i = 0; i < COUNT; ++i) {
   1772         log_verbose("\n\ntesting format %d\n", i);
   1773         test_fmt(formats[i], (UBool)(i == 0));
   1774     }
   1775 
   1776     #define FORMAT_BUF_CAPACITY 64
   1777     {
   1778         UChar fmtbuf[FORMAT_BUF_CAPACITY];
   1779         int32_t len;
   1780         double nanvalue = uprv_getNaN();
   1781         status = U_ZERO_ERROR;
   1782         len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
   1783         if (U_FAILURE(status)) {
   1784             log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status));
   1785         } else {
   1786             UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
   1787             if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) {
   1788                 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
   1789             }
   1790         }
   1791     }
   1792 
   1793     for (i = 0; i < COUNT; ++i) {
   1794         unum_close(formats[i]);
   1795     }
   1796 }
   1797 
   1798 static void TestRBNFRounding() {
   1799     UChar fmtbuf[FORMAT_BUF_CAPACITY];
   1800     UChar expectedBuf[FORMAT_BUF_CAPACITY];
   1801     int32_t len;
   1802     UErrorCode status = U_ZERO_ERROR;
   1803     UNumberFormat* fmt = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", NULL, &status);
   1804     if (U_FAILURE(status)) {
   1805         log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
   1806         return;
   1807     }
   1808     len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
   1809     if (U_FAILURE(status)) {
   1810         log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
   1811     }
   1812     u_uastrcpy(expectedBuf, "ten point one two three four five six seven eight nine");
   1813     if (u_strcmp(expectedBuf, fmtbuf) != 0) {
   1814         log_err("Wrong result for unrounded value\n");
   1815     }
   1816     unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 3);
   1817     if (unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS) != 3) {
   1818         log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS));
   1819     }
   1820     if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_UNNECESSARY) {
   1821         log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
   1822     }
   1823     unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP);
   1824     if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_HALFUP) {
   1825         log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
   1826     }
   1827     len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
   1828     if (U_FAILURE(status)) {
   1829         log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
   1830     }
   1831     u_uastrcpy(expectedBuf, "ten point one two three");
   1832     if (u_strcmp(expectedBuf, fmtbuf) != 0) {
   1833         char temp[512];
   1834         u_austrcpy(temp, fmtbuf);
   1835         log_err("Wrong result for rounded value. Got: %s\n", temp);
   1836     }
   1837     unum_close(fmt);
   1838 }
   1839 
   1840 static void TestCurrencyRegression(void) {
   1841 /*
   1842  I've found a case where unum_parseDoubleCurrency is not doing what I
   1843 expect.  The value I pass in is $1234567890q123460000.00 and this
   1844 returns with a status of zero error & a parse pos of 22 (I would
   1845 expect a parse error at position 11).
   1846 
   1847 I stepped into DecimalFormat::subparse() and it looks like it parses
   1848 the first 10 digits and then stops parsing at the q but doesn't set an
   1849 error. Then later in DecimalFormat::parse() the value gets crammed
   1850 into a long (which greatly truncates the value).
   1851 
   1852 This is very problematic for me 'cause I try to remove chars that are
   1853 invalid but this allows my users to enter bad chars and truncates
   1854 their data!
   1855 */
   1856 
   1857     UChar buf[1024];
   1858     UChar currency[8];
   1859     char acurrency[16];
   1860     double d;
   1861     UNumberFormat *cur;
   1862     int32_t pos;
   1863     UErrorCode status  = U_ZERO_ERROR;
   1864     const int32_t expected = 11;
   1865 
   1866     currency[0]=0;
   1867     u_uastrcpy(buf, "$1234567890q643210000.00");
   1868     cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status);
   1869 
   1870     if(U_FAILURE(status)) {
   1871         log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
   1872         return;
   1873     }
   1874 
   1875     status = U_ZERO_ERROR; /* so we can test it later. */
   1876     pos = 0;
   1877 
   1878     d = unum_parseDoubleCurrency(cur,
   1879                          buf,
   1880                          -1,
   1881                          &pos, /* 0 = start */
   1882                          currency,
   1883                          &status);
   1884 
   1885     u_austrcpy(acurrency, currency);
   1886 
   1887     if(U_FAILURE(status) || (pos != expected)) {
   1888         log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
   1889             expected, d, u_errorName(status), pos, acurrency);
   1890     } else {
   1891         log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency);
   1892     }
   1893 
   1894     unum_close(cur);
   1895 }
   1896 
   1897 static void TestTextAttributeCrash(void) {
   1898     UChar ubuffer[64] = {0x0049,0x004E,0x0052,0};
   1899     static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
   1900     static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
   1901     int32_t used;
   1902     UErrorCode status = U_ZERO_ERROR;
   1903     UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
   1904     if (U_FAILURE(status)) {
   1905         log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
   1906         return;
   1907     }
   1908     unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status);
   1909     /*
   1910      * the usual negative prefix and suffix seem to be '($' and ')' at this point
   1911      * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
   1912      */
   1913     used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status);
   1914     unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status);
   1915     if (U_FAILURE(status)) {
   1916         log_err("FAILED 2\n"); exit(1);
   1917     }
   1918     log_verbose("attempting to format...\n");
   1919     used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
   1920     if (U_FAILURE(status) || 64 < used) {
   1921         log_err("Failed formatting %s\n", u_errorName(status));
   1922         return;
   1923     }
   1924     if (u_strcmp(expectedNeg, ubuffer) == 0) {
   1925         log_err("Didn't get expected negative result\n");
   1926     }
   1927     used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
   1928     if (U_FAILURE(status) || 64 < used) {
   1929         log_err("Failed formatting %s\n", u_errorName(status));
   1930         return;
   1931     }
   1932     if (u_strcmp(expectedPos, ubuffer) == 0) {
   1933         log_err("Didn't get expected positive result\n");
   1934     }
   1935     unum_close(nf);
   1936 }
   1937 
   1938 static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
   1939     UErrorCode status = U_ZERO_ERROR;
   1940     UChar myString[20];
   1941     char tmpbuf[200];
   1942     double aNumber = -1.0;
   1943     unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
   1944     log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
   1945     if(U_FAILURE(status)) {
   1946       log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
   1947         return;
   1948     }
   1949     aNumber = unum_parse(nf, myString, -1, NULL, &status);
   1950     if(U_FAILURE(status)) {
   1951       log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
   1952         return;
   1953     }
   1954     if(uprv_fabs(aNumber-myNumber)>.001) {
   1955       log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
   1956     } else {
   1957       log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
   1958     }
   1959 }
   1960 
   1961 static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
   1962   TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
   1963   TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
   1964 }
   1965 
   1966 static void TestNBSPInPattern(void) {
   1967     UErrorCode status = U_ZERO_ERROR;
   1968     UNumberFormat* nf = NULL;
   1969     const char *testcase;
   1970 
   1971 
   1972     testcase="ar_AE UNUM_CURRENCY";
   1973     nf  = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
   1974     if(U_FAILURE(status) || nf == NULL) {
   1975       log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
   1976         return;
   1977     }
   1978     TestNBSPPatternRT(testcase, nf);
   1979 
   1980     /* if we don't have CLDR 1.6 data, bring out the problem anyways */
   1981     {
   1982 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
   1983         UChar pat[200];
   1984         testcase = "ar_AE special pattern: " SPECIAL_PATTERN;
   1985         u_unescape(SPECIAL_PATTERN, pat, UPRV_LENGTHOF(pat));
   1986         unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
   1987         if(U_FAILURE(status)) {
   1988             log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status));
   1989         } else {
   1990             TestNBSPPatternRT(testcase, nf);
   1991         }
   1992 #undef SPECIAL_PATTERN
   1993     }
   1994     unum_close(nf); status = U_ZERO_ERROR;
   1995 
   1996     testcase="ar_AE UNUM_DECIMAL";
   1997     nf  = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status);
   1998     if(U_FAILURE(status)) {
   1999         log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
   2000     }
   2001     TestNBSPPatternRT(testcase, nf);
   2002     unum_close(nf); status = U_ZERO_ERROR;
   2003 
   2004     testcase="ar_AE UNUM_PERCENT";
   2005     nf  = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status);
   2006     if(U_FAILURE(status)) {
   2007         log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
   2008     }
   2009     TestNBSPPatternRT(testcase, nf);
   2010     unum_close(nf); status = U_ZERO_ERROR;
   2011 
   2012 
   2013 
   2014 }
   2015 static void TestCloneWithRBNF(void) {
   2016     UChar pattern[1024];
   2017     UChar pat2[512];
   2018     UErrorCode status = U_ZERO_ERROR;
   2019     UChar buffer[256];
   2020     UChar buffer_cloned[256];
   2021     char temp1[256];
   2022     char temp2[256];
   2023     UNumberFormat *pform_cloned;
   2024     UNumberFormat *pform;
   2025 
   2026     u_uastrcpy(pattern,
   2027         "%main:\n"
   2028         "0.x: >%%millis-only>;\n"
   2029         "x.0: <%%duration<;\n"
   2030         "x.x: <%%durationwithmillis<>%%millis-added>;\n"
   2031         "-x: ->>;%%millis-only:\n"
   2032         "1000: 00:00.<%%millis<;\n"
   2033         "%%millis-added:\n"
   2034         "1000: .<%%millis<;\n"
   2035         "%%millis:\n"
   2036         "0: =000=;\n"
   2037         "%%duration:\n"
   2038         "0: =%%seconds-only=;\n"
   2039         "60: =%%min-sec=;\n"
   2040         "3600: =%%hr-min-sec=;\n"
   2041         "86400/86400: <%%ddaayyss<[, >>];\n"
   2042         "%%durationwithmillis:\n"
   2043         "0: =%%seconds-only=;\n"
   2044         "60: =%%min-sec=;\n"
   2045         "3600: =%%hr-min-sec=;\n"
   2046         "86400/86400: <%%ddaayyss<, >>;\n");
   2047     u_uastrcpy(pat2,
   2048         "%%seconds-only:\n"
   2049         "0: 0:00:=00=;\n"
   2050         "%%min-sec:\n"
   2051         "0: :=00=;\n"
   2052         "0/60: 0:<00<>>;\n"
   2053         "%%hr-min-sec:\n"
   2054         "0: :=00=;\n"
   2055         "60/60: <00<>>;\n"
   2056         "3600/60: <0<:>>>;\n"
   2057         "%%ddaayyss:\n"
   2058         "0 days;\n"
   2059         "1 day;\n"
   2060         "=0= days;");
   2061 
   2062     /* This is to get around some compiler warnings about char * string length. */
   2063     u_strcat(pattern, pat2);
   2064 
   2065     pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status);
   2066     unum_formatDouble(pform, 3600, buffer, 256, NULL, &status);
   2067 
   2068     pform_cloned = unum_clone(pform,&status);
   2069     unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status);
   2070 
   2071     unum_close(pform);
   2072     unum_close(pform_cloned);
   2073 
   2074     if (u_strcmp(buffer,buffer_cloned)) {
   2075         log_data_err("Result from cloned formatter not identical to the original. Original: %s Cloned: %s - (Are you missing data?)",u_austrcpy(temp1, buffer),u_austrcpy(temp2,buffer_cloned));
   2076     }
   2077 }
   2078 
   2079 
   2080 static void TestNoExponent(void) {
   2081     UErrorCode status = U_ZERO_ERROR;
   2082     UChar str[100];
   2083     const char *cstr;
   2084     UNumberFormat *fmt;
   2085     int32_t pos;
   2086     int32_t expect = 0;
   2087     int32_t num;
   2088 
   2089     fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status);
   2090 
   2091     if(U_FAILURE(status) || fmt == NULL) {
   2092         log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status));
   2093         return;
   2094     }
   2095 
   2096     cstr = "10E6";
   2097     u_uastrcpy(str, cstr);
   2098     expect = 10000000;
   2099     pos = 0;
   2100     num = unum_parse(fmt, str, -1, &pos, &status);
   2101     ASSERT_TRUE(pos==4);
   2102     if(U_FAILURE(status)) {
   2103         log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
   2104     } else if(expect!=num) {
   2105         log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
   2106     } else {
   2107         log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
   2108     }
   2109 
   2110     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
   2111 
   2112     unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
   2113     log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
   2114 
   2115     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
   2116 
   2117     pos = 0;
   2118     expect=10;
   2119     num = unum_parse(fmt, str, -1, &pos, &status);
   2120     if(num==10000000) {
   2121         log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr);
   2122     } else if(num==expect) {
   2123         log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr);
   2124     }
   2125     ASSERT_TRUE(pos==2);
   2126 
   2127     status = U_ZERO_ERROR;
   2128 
   2129     unum_close(fmt);
   2130 
   2131     /* ok, now try scientific */
   2132     fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status);
   2133     assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status);
   2134 
   2135     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
   2136 
   2137     cstr = "10E6";
   2138     u_uastrcpy(str, cstr);
   2139     expect = 10000000;
   2140     pos = 0;
   2141     num = unum_parse(fmt, str, -1, &pos, &status);
   2142     ASSERT_TRUE(pos==4);
   2143     if(U_FAILURE(status)) {
   2144         log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
   2145     } else if(expect!=num) {
   2146         log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
   2147     } else {
   2148         log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
   2149     }
   2150 
   2151     unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
   2152     log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
   2153 
   2154     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
   2155 
   2156 
   2157     cstr = "10E6";
   2158     u_uastrcpy(str, cstr);
   2159     expect = 10000000;
   2160     pos = 0;
   2161     num = unum_parse(fmt, str, -1, &pos, &status);
   2162     ASSERT_TRUE(pos==4);
   2163     if(U_FAILURE(status)) {
   2164         log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
   2165     } else if(expect!=num) {
   2166         log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
   2167     } else {
   2168         log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
   2169     }
   2170 
   2171     unum_close(fmt);
   2172 }
   2173 
   2174 static void TestMaxInt(void) {
   2175     UErrorCode status = U_ZERO_ERROR;
   2176     UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */
   2177     UChar result1[1024] = { 0 }, result2[1024] = { 0 };
   2178     int32_t len1, len2;
   2179     UChar expect[] = { 0x0039, 0x0037, 0 };
   2180     UNumberFormat *fmt = unum_open(
   2181                   UNUM_PATTERN_DECIMAL,      /* style         */
   2182                   &pattern_hash[0],          /* pattern       */
   2183                   u_strlen(pattern_hash),    /* patternLength */
   2184                   0,
   2185                   0,                         /* parseErr      */
   2186                   &status);
   2187     if(U_FAILURE(status) || fmt == NULL) {
   2188         log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status));
   2189         return;
   2190     }
   2191 
   2192     unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2);
   2193 
   2194     status = U_ZERO_ERROR;
   2195     /* #1 */
   2196     len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
   2197     result1[len1]=0;
   2198     if(U_FAILURE(status) || u_strcmp(expect, result1)) {
   2199         log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
   2200     }
   2201 
   2202     status = U_ZERO_ERROR;
   2203     /* #2 */
   2204     len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status);
   2205     result2[len2]=0;
   2206     if(U_FAILURE(status) || u_strcmp(expect, result2)) {
   2207         log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
   2208     }
   2209 
   2210 
   2211 
   2212     /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
   2213     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0);
   2214 
   2215     unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1);
   2216     /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
   2217     ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1);
   2218 
   2219     status = U_ZERO_ERROR;
   2220     /* max int digits still '2' */
   2221     len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
   2222     ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR);
   2223     status = U_ZERO_ERROR;
   2224 
   2225     /* But, formatting 97->'97' works fine. */
   2226 
   2227     /* #1 */
   2228     len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status);
   2229     result1[len1]=0;
   2230     if(U_FAILURE(status) || u_strcmp(expect, result1)) {
   2231         log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
   2232     }
   2233 
   2234     status = U_ZERO_ERROR;
   2235     /* #2 */
   2236     len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status);
   2237     result2[len2]=0;
   2238     if(U_FAILURE(status) || u_strcmp(expect, result2)) {
   2239         log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
   2240     }
   2241 
   2242 
   2243     unum_close(fmt);
   2244 }
   2245 
   2246 static void TestUFormattable(void) {
   2247   UChar out2k[2048];
   2248   // simple test for API docs
   2249   {
   2250     UErrorCode status = U_ZERO_ERROR;
   2251     UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
   2252     if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
   2253       //! [unum_parseToUFormattable]
   2254       const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
   2255       int32_t result = 0;
   2256       UFormattable *ufmt = ufmt_open(&status);
   2257       unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status);
   2258       if (ufmt_isNumeric(ufmt)) {
   2259           result = ufmt_getLong(ufmt, &status); /* == 123 */
   2260       } /* else { ... } */
   2261       ufmt_close(ufmt);
   2262       //! [unum_parseToUFormattable]
   2263       assertTrue("result == 123", (result == 123));
   2264     }
   2265     unum_close(unum);
   2266   }
   2267   // test with explicitly created ufmt_open
   2268   {
   2269     UChar buffer[2048];
   2270     UErrorCode status = U_ZERO_ERROR;
   2271     UFormattable *ufmt;
   2272     UNumberFormat *unum;
   2273     const char *pattern = "";
   2274 
   2275     ufmt = ufmt_open(&status);
   2276     unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
   2277     if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) {
   2278 
   2279       pattern = "31337";
   2280       log_verbose("-- pattern: %s\n", pattern);
   2281       u_uastrcpy(buffer, pattern);
   2282       unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
   2283       if(assertSuccess("unum_parseToUFormattable(31337)", &status)) {
   2284         assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337);
   2285         assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG);
   2286         log_verbose("long = %d\n", ufmt_getLong(ufmt, &status));
   2287         assertSuccess("ufmt_getLong()", &status);
   2288       }
   2289       unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
   2290       if(assertSuccess("unum_formatUFormattable(31337)", &status)) {
   2291         assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
   2292       }
   2293 
   2294       pattern = "3.14159";
   2295       log_verbose("-- pattern: %s\n", pattern);
   2296       u_uastrcpy(buffer, pattern);
   2297       unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
   2298       if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) {
   2299         assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15));
   2300         assertSuccess("ufmt_getDouble()", &status);
   2301         assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE);
   2302         log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status));
   2303       }
   2304       unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
   2305       if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
   2306         assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
   2307       }
   2308     }
   2309     ufmt_close(ufmt);
   2310     unum_close(unum);
   2311   }
   2312 
   2313   // test with auto-generated ufmt
   2314   {
   2315     UChar buffer[2048];
   2316     UErrorCode status = U_ZERO_ERROR;
   2317     UFormattable *ufmt = NULL;
   2318     UNumberFormat *unum;
   2319     const char *pattern = "73476730924573500000000"; // weight of the moon, kg
   2320 
   2321     log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern);
   2322     u_uastrcpy(buffer, pattern);
   2323 
   2324     unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
   2325     if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
   2326 
   2327       ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */
   2328                                    buffer, -1, NULL, &status);
   2329       if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) {
   2330         log_verbose("new formattable allocated at %p\n", (void*)ufmt);
   2331         assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt));
   2332         unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
   2333         if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
   2334           assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
   2335         }
   2336 
   2337         log_verbose("double: %g\n",  ufmt_getDouble(ufmt, &status));
   2338         assertSuccess("ufmt_getDouble()", &status);
   2339 
   2340         log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status));
   2341         assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status));
   2342         // status is now a failure due to ufmt_getLong() above.
   2343         // the intltest does extensive r/t testing of Formattable vs. UFormattable.
   2344       }
   2345     }
   2346 
   2347     unum_close(unum);
   2348     ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable()
   2349   }
   2350 }
   2351 
   2352 typedef struct {
   2353     const char*  locale;
   2354     const char*  numsys;
   2355     int32_t      radix;
   2356     UBool        isAlgorithmic;
   2357     const UChar* description;
   2358 } NumSysTestItem;
   2359 
   2360 
   2361 static const UChar latnDesc[]    = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
   2362 static const UChar romanDesc[]   = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
   2363 static const UChar arabDesc[]    = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
   2364 static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
   2365 static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
   2366 static const UChar hantDesc[]    = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
   2367                                     0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
   2368                                     0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
   2369 
   2370 static const NumSysTestItem numSysTestItems[] = {
   2371     //locale                         numsys    radix isAlgo  description
   2372     { "en",                          "latn",    10,  FALSE,  latnDesc },
   2373     { "en@numbers=roman",            "roman",   10,  TRUE,   romanDesc },
   2374     { "en@numbers=finance",          "latn",    10,  FALSE,  latnDesc },
   2375     { "ar",                          "arab",    10,  FALSE,  arabDesc },
   2376     { "fa",                          "arabext", 10,  FALSE,  arabextDesc },
   2377     { "zh_Hans@numbers=hanidec",     "hanidec", 10,  FALSE,  hanidecDesc },
   2378     { "zh_Hant@numbers=traditional", "hant",    10,  TRUE,   hantDesc },
   2379     { NULL,                          NULL,       0,  FALSE,  NULL },
   2380 };
   2381 enum { kNumSysDescripBufMax = 64 };
   2382 
   2383 static void TestUNumberingSystem(void) {
   2384     const NumSysTestItem * itemPtr;
   2385     UNumberingSystem * unumsys;
   2386     UEnumeration * uenum;
   2387     const char * numsys;
   2388     UErrorCode status;
   2389 
   2390     for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) {
   2391         status = U_ZERO_ERROR;
   2392         unumsys = unumsys_open(itemPtr->locale, &status);
   2393         if ( U_SUCCESS(status) ) {
   2394             UChar ubuf[kNumSysDescripBufMax];
   2395             int32_t ulen, radix = unumsys_getRadix(unumsys);
   2396             UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys);
   2397             numsys = unumsys_getName(unumsys);
   2398             if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) {
   2399                 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
   2400                         itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic);
   2401             }
   2402             ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status);
   2403             (void)ulen;   // Suppress variable not used warning.
   2404             if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) {
   2405                 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status));
   2406             }
   2407             unumsys_close(unumsys);
   2408         } else {
   2409             log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status));
   2410         }
   2411     }
   2412 
   2413     status = U_ZERO_ERROR;
   2414     uenum = unumsys_openAvailableNames(&status);
   2415     if ( U_SUCCESS(status) ) {
   2416         int32_t numsysCount = 0;
   2417         // sanity check for a couple of number systems that must be in the enumeration
   2418         UBool foundLatn = FALSE;
   2419         UBool foundArab = FALSE;
   2420         while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
   2421             status = U_ZERO_ERROR;
   2422             unumsys = unumsys_openByName(numsys, &status);
   2423             if ( U_SUCCESS(status) ) {
   2424                 numsysCount++;
   2425                 if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
   2426                 if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
   2427                 unumsys_close(unumsys);
   2428             } else {
   2429                 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
   2430                         numsys, myErrorName(status));
   2431             }
   2432         }
   2433         uenum_close(uenum);
   2434         if ( numsysCount < 40 || !foundLatn || !foundArab ) {
   2435             log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
   2436                     numsysCount, foundLatn, foundArab);
   2437         }
   2438     } else {
   2439         log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
   2440     }
   2441 }
   2442 
   2443 /* plain-C version of test in numfmtst.cpp */
   2444 enum { kUBufMax = 64 };
   2445 static void TestCurrencyIsoPluralFormat(void) {
   2446     static const char* DATA[][8] = {
   2447         // the data are:
   2448         // locale,
   2449         // currency amount to be formatted,
   2450         // currency ISO code to be formatted,
   2451         // format result using CURRENCYSTYLE,
   2452         // format result using CURRENCY_STANDARD,
   2453         // format result using CURRENCY_ACCOUNTING,
   2454         // format result using ISOCURRENCYSTYLE,
   2455         // format result using PLURALCURRENCYSTYLE,
   2456 
   2457         // locale             amount     ISOcode CURRENCYSTYLE         CURRENCY_STANDARD     CURRENCY_ACCOUNTING   ISOCURRENCYSTYLE  PLURALCURRENCYSTYLE
   2458         {"en_US",             "1",        "USD", "$1.00",              "$1.00",              "$1.00",              "USD1.00",        "1.00 US dollars"},
   2459         {"en_US",             "1234.56",  "USD", "$1,234.56",          "$1,234.56",          "$1,234.56",          "USD1,234.56",    "1,234.56 US dollars"},
   2460         {"en_US@cf=account",  "1234.56",  "USD", "$1,234.56",          "$1,234.56",          "$1,234.56",          "USD1,234.56",    "1,234.56 US dollars"},
   2461         {"en_US",             "-1234.56", "USD", "-$1,234.56",         "-$1,234.56",         "($1,234.56)",        "-USD1,234.56",   "-1,234.56 US dollars"},
   2462         {"en_US@cf=account",  "-1234.56", "USD", "($1,234.56)",        "-$1,234.56",         "($1,234.56)",        "-USD1,234.56",   "-1,234.56 US dollars"},
   2463         {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56",         "-$1,234.56",         "($1,234.56)",        "-USD1,234.56",   "-1,234.56 US dollars"},
   2464         {"zh_CN",             "1",        "USD", "US$1.00",            "US$1.00",            "US$1.00",            "USD1.00",        "1.00\\u7F8E\\u5143"},
   2465         {"zh_CN",             "-1",       "USD", "-US$1.00",           "-US$1.00",           "(US$1.00)",          "-USD1.00",       "-1.00\\u7F8E\\u5143"},
   2466         {"zh_CN@cf=account",  "-1",       "USD", "(US$1.00)",          "-US$1.00",           "(US$1.00)",          "-USD1.00",       "-1.00\\u7F8E\\u5143"},
   2467         {"zh_CN@cf=standard", "-1",       "USD", "-US$1.00",           "-US$1.00",           "(US$1.00)",          "-USD1.00",       "-1.00\\u7F8E\\u5143"},
   2468         {"zh_CN",             "1234.56",  "USD", "US$1,234.56",        "US$1,234.56",        "US$1,234.56",        "USD1,234.56",    "1,234.56\\u7F8E\\u5143"},
   2469         // {"zh_CN",          "1",        "CHY", "CHY1.00",            "CHY1.00",            "CHY1.00",            "CHY1.00",        "1.00 CHY"}, // wrong ISO code
   2470         // {"zh_CN",          "1234.56",  "CHY", "CHY1,234.56",        "CHY1,234.56",        "CHY1,234.56",        "CHY1,234.56",    "1,234.56 CHY"}, // wrong ISO code
   2471         {"zh_CN",             "1",        "CNY", "\\uFFE51.00",        "\\uFFE51.00",        "\\uFFE51.00",        "CNY1.00",        "1.00\\u4EBA\\u6C11\\u5E01"},
   2472         {"zh_CN",             "1234.56",  "CNY", "\\uFFE51,234.56",    "\\uFFE51,234.56",    "\\uFFE51,234.56",    "CNY1,234.56",    "1,234.56\\u4EBA\\u6C11\\u5E01"},
   2473         {"ru_RU",             "1",        "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
   2474                                                                                                                                            "\\u0440\\u0443\\u0431\\u043B\\u044F"},
   2475         {"ru_RU",             "2",        "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
   2476                                                                                                                                            "\\u0440\\u0443\\u0431\\u043B\\u044F"},
   2477         {"ru_RU",             "5",        "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
   2478                                                                                                                                            "\\u0440\\u0443\\u0431\\u043B\\u044F"},
   2479         // test locale without currency information
   2480         {"root",              "-1.23",    "USD", "-US$\\u00A01.23",    "-US$\\u00A01.23",    "-US$\\u00A01.23",    "-USD\\u00A01.23", "-1.23 USD"},
   2481         {"root@cf=account",   "-1.23",    "USD", "-US$\\u00A01.23",    "-US$\\u00A01.23",    "-US$\\u00A01.23",    "-USD\\u00A01.23", "-1.23 USD"},
   2482         // test choice format
   2483         {"es_AR",             "1",        "INR", "INR\\u00A01,00",     "INR\\u00A01,00",     "INR\\u00A01,00",     "INR\\u00A01,00",  "1,00 rupia india"},
   2484     };
   2485     static const UNumberFormatStyle currencyStyles[] = {
   2486         UNUM_CURRENCY,
   2487         UNUM_CURRENCY_STANDARD,
   2488         UNUM_CURRENCY_ACCOUNTING,
   2489         UNUM_CURRENCY_ISO,
   2490         UNUM_CURRENCY_PLURAL
   2491     };
   2492 
   2493     int32_t i, sIndex;
   2494 
   2495     for (i=0; i<UPRV_LENGTHOF(DATA); ++i) {
   2496       const char* localeString = DATA[i][0];
   2497       double numberToBeFormat = atof(DATA[i][1]);
   2498       const char* currencyISOCode = DATA[i][2];
   2499       for (sIndex = 0; sIndex < UPRV_LENGTHOF(currencyStyles); ++sIndex) {
   2500         UNumberFormatStyle style = currencyStyles[sIndex];
   2501         UErrorCode status = U_ZERO_ERROR;
   2502         UChar currencyCode[4];
   2503         UChar ubufResult[kUBufMax];
   2504         UChar ubufExpected[kUBufMax];
   2505         int32_t ulenRes;
   2506 
   2507         UNumberFormat* unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
   2508         if (U_FAILURE(status)) {
   2509             log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString, (int)style, myErrorName(status));
   2510             continue;
   2511         }
   2512         u_charsToUChars(currencyISOCode, currencyCode, 4);
   2513         unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
   2514         if (U_FAILURE(status)) {
   2515             log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s\n", localeString, currencyISOCode);
   2516         }
   2517         ulenRes = unum_formatDouble(unumFmt, numberToBeFormat, ubufResult, kUBufMax, NULL, &status);
   2518         if (U_FAILURE(status)) {
   2519             log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s - %s\n", localeString, currencyISOCode, myErrorName(status));
   2520         } else {
   2521             int32_t ulenExp = u_unescape(DATA[i][3 + sIndex], ubufExpected, kUBufMax);
   2522             if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
   2523                 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got something else\n",
   2524                         localeString, currencyISOCode, DATA[i][3 + sIndex]);
   2525             }
   2526         }
   2527         unum_close(unumFmt);
   2528       }
   2529     }
   2530 }
   2531 
   2532 typedef struct {
   2533     const char * locale;
   2534     UNumberFormatStyle style;
   2535     UDisplayContext context;
   2536     const char * expectedResult;
   2537 } TestContextItem;
   2538 
   2539 /* currently no locales have contextTransforms data for "symbol" type */
   2540 static const TestContextItem tcItems[] = { /* results for 123.45 */
   2541     { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
   2542     { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
   2543     { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
   2544     { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
   2545     { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    "one hundred twenty-three point four five" },
   2546     { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "One hundred twenty-three point four five" },
   2547     { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       "One hundred twenty-three point four five" },
   2548     { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            "One hundred twenty-three point four five" },
   2549     { NULL, (UNumberFormatStyle)0, (UDisplayContext)0, NULL }
   2550 };
   2551 
   2552 static void TestContext(void) {
   2553     UErrorCode status = U_ZERO_ERROR;
   2554     const TestContextItem* itemPtr;
   2555 
   2556     UNumberFormat *unum = unum_open(UNUM_SPELLOUT, NULL, 0, "en", NULL, &status);
   2557     if ( U_SUCCESS(status) ) {
   2558         UDisplayContext context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
   2559         if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_NONE) {
   2560             log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n");
   2561             status = U_ZERO_ERROR;
   2562         }
   2563         unum_setContext(unum, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
   2564         context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
   2565         if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
   2566             log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n");
   2567         }
   2568         unum_close(unum);
   2569     } else {
   2570         log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status));
   2571     }
   2572 #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION
   2573     for (itemPtr = tcItems; itemPtr->locale != NULL; itemPtr++) {
   2574         UChar ubufResult[kUBufMax];
   2575         int32_t ulenRes;
   2576 
   2577         status = U_ZERO_ERROR;
   2578         unum = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
   2579         if (U_FAILURE(status)) {
   2580             log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
   2581                         itemPtr->locale, (int)itemPtr->style, myErrorName(status));
   2582             continue;
   2583         }
   2584         unum_setContext(unum, itemPtr->context, &status);
   2585         ulenRes = unum_formatDouble(unum, 123.45, ubufResult, kUBufMax, NULL, &status);
   2586         if (U_FAILURE(status)) {
   2587             log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
   2588                     itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, myErrorName(status));
   2589         } else {
   2590             UChar ubufExpected[kUBufMax];
   2591             int32_t ulenExp = u_unescape(itemPtr->expectedResult, ubufExpected, kUBufMax);
   2592             if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
   2593                 char bbuf[kUBufMax*2];
   2594                 u_austrncpy(bbuf, ubufResult, sizeof(bbuf));
   2595                 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
   2596                         itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, ulenExp,
   2597                         itemPtr->expectedResult, ulenRes, bbuf);
   2598             }
   2599         }
   2600         unum_close(unum);
   2601     }
   2602 #endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */
   2603 }
   2604 
   2605 static void TestCurrencyUsage(void) {
   2606     static const char* DATA[][2] = {
   2607         /* the data are:
   2608          * currency ISO code to be formatted,
   2609          * format result using CURRENCYSTYLE with CASH purpose,-
   2610          * Note that as of CLDR 26:-
   2611          * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
   2612          * - CAD rounds to .05
   2613          */
   2614 
   2615         {"PKR", "PKR124"},
   2616         {"CAD", "CA$123.55"},
   2617         {"USD", "$123.57"}
   2618     };
   2619 
   2620     // 1st time for getter/setter, 2nd for factory method
   2621     int32_t i;
   2622     for(i=0; i<2; i++){
   2623         const char* localeString = "en_US";
   2624         double numberToBeFormat = 123.567;
   2625         UNumberFormat* unumFmt;
   2626         UNumberFormatStyle style = UNUM_CURRENCY;
   2627         UErrorCode status = U_ZERO_ERROR;
   2628         int32_t j;
   2629 
   2630         if(i == 1){ // change for factory method
   2631             style = UNUM_CASH_CURRENCY;
   2632         }
   2633 
   2634         unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
   2635         if (U_FAILURE(status)) {
   2636             log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
   2637                         localeString, (int)style, myErrorName(status));
   2638             continue;
   2639         }
   2640 
   2641         if(i == 0){ // this is for the getter/setter
   2642             if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_STANDARD) {
   2643                 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n");
   2644             }
   2645 
   2646             unum_setAttribute(unumFmt, UNUM_CURRENCY_USAGE, UCURR_USAGE_CASH);
   2647         }
   2648 
   2649         if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_CASH) {
   2650             log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n");
   2651         }
   2652 
   2653         for (j=0; j<UPRV_LENGTHOF(DATA); ++j) {
   2654             UChar expect[64];
   2655             int32_t expectLen;
   2656             UChar currencyCode[4];
   2657             UChar result[64];
   2658             int32_t resultLen;
   2659             UFieldPosition pos = {0};
   2660 
   2661             u_charsToUChars(DATA[j][0], currencyCode, 3);
   2662             expectLen = u_unescape(DATA[j][1], expect, UPRV_LENGTHOF(expect));
   2663 
   2664             unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
   2665             assertSuccess("num_setTextAttribute()", &status);
   2666 
   2667             resultLen = unum_formatDouble(unumFmt, numberToBeFormat, result, UPRV_LENGTHOF(result),
   2668                                         &pos, &status);
   2669             assertSuccess("num_formatDouble()", &status);
   2670 
   2671             if(resultLen != expectLen || u_strcmp(result, expect) != 0) {
   2672                 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n",
   2673                 aescstrdup(expect, expectLen), aescstrdup(result, resultLen));
   2674             }
   2675 
   2676         }
   2677 
   2678         unum_close(unumFmt);
   2679     }
   2680 }
   2681 
   2682 static UChar currFmtNegSameAsPos[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */
   2683     {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
   2684 
   2685 static UChar currFmtToPatExpected[] = /* "\u00A4#,##0.00" */
   2686     {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
   2687 
   2688 static UChar currFmtResultExpected[] = /* "$100.00" */
   2689     {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0};
   2690 
   2691 static UChar emptyString[] = {0};
   2692 
   2693 enum { kUBufSize = 64, kBBufSize = 128 };
   2694 
   2695 static void TestCurrFmtNegSameAsPositive(void) {
   2696     UErrorCode status = U_ZERO_ERROR;
   2697     UNumberFormat* unumfmt = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
   2698     if ( U_SUCCESS(status) ) {
   2699         unum_applyPattern(unumfmt, FALSE, currFmtNegSameAsPos, -1, NULL, &status);
   2700         if (U_SUCCESS(status)) {
   2701             UChar ubuf[kUBufSize];
   2702             int32_t ulen = unum_toPattern(unumfmt, FALSE, ubuf, kUBufSize, &status);
   2703             if (U_FAILURE(status)) {
   2704                 log_err("unum_toPattern fails with status %s\n", myErrorName(status));
   2705             } else if (u_strcmp(ubuf, currFmtToPatExpected) != 0) {
   2706                 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected,-1), aescstrdup(ubuf,ulen));
   2707             }
   2708             unum_setSymbol(unumfmt, UNUM_MINUS_SIGN_SYMBOL, emptyString, 0, &status);
   2709             if (U_SUCCESS(status)) {
   2710                 ulen = unum_formatDouble(unumfmt, -100.0, ubuf, kUBufSize, NULL, &status);
   2711                 if (U_FAILURE(status)) {
   2712                     log_err("unum_formatDouble fails with status %s\n", myErrorName(status));
   2713                 } else if (u_strcmp(ubuf, currFmtResultExpected) != 0) {
   2714                     log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected,-1), aescstrdup(ubuf,ulen));
   2715                 }
   2716             } else {
   2717                 log_err("unum_setSymbol fails with status %s\n", myErrorName(status));
   2718             }
   2719         } else {
   2720             log_err("unum_applyPattern fails with status %s\n", myErrorName(status));
   2721         }
   2722         unum_close(unumfmt);
   2723     } else {
   2724         log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status));
   2725     }
   2726 }
   2727 
   2728 
   2729 typedef struct {
   2730   double value;
   2731   const char *expected;
   2732 } ValueAndExpectedString;
   2733 
   2734 static const ValueAndExpectedString enShort[] = {
   2735   {0.0, "0"},
   2736   {0.17, "0.17"},
   2737   {1.0, "1"},
   2738   {1234.0, "1.23K"},
   2739   {12345.0, "12.3K"},
   2740   {123456.0, "123K"},
   2741   {1234567.0, "1.23M"},
   2742   {12345678.0, "12.3M"},
   2743   {123456789.0, "123M"},
   2744   {1.23456789E9, "1.23B"},
   2745   {1.23456789E10, "12.3B"},
   2746   {1.23456789E11, "123B"},
   2747   {1.23456789E12, "1.23T"},
   2748   {1.23456789E13, "12.3T"},
   2749   {1.23456789E14, "123T"},
   2750   {1.23456789E15, "1230T"},
   2751   {0.0, NULL}
   2752 };
   2753 
   2754 static const ValueAndExpectedString enShortMax2[] = {
   2755   {0.0, "0"},
   2756   {0.17, "0.17"},
   2757   {1.0, "1"},
   2758   {1234.0, "1.2K"},
   2759   {12345.0, "12K"},
   2760   {123456.0, "120K"},
   2761   {1234567.0, "1.2M"},
   2762   {12345678.0, "12M"},
   2763   {123456789.0, "120M"},
   2764   {1.23456789E9, "1.2B"},
   2765   {1.23456789E10, "12B"},
   2766   {1.23456789E11, "120B"},
   2767   {1.23456789E12, "1.2T"},
   2768   {1.23456789E13, "12T"},
   2769   {1.23456789E14, "120T"},
   2770   {1.23456789E15, "1200T"},
   2771   {0.0, NULL}
   2772 };
   2773 
   2774 static const ValueAndExpectedString enShortMax5[] = {
   2775   {0.0, "0"},
   2776   {0.17, "0.17"},
   2777   {1.0, "1"},
   2778   {1234.0, "1.234K"},
   2779   {12345.0, "12.345K"},
   2780   {123456.0, "123.46K"},
   2781   {1234567.0, "1.2346M"},
   2782   {12345678.0, "12.346M"},
   2783   {123456789.0, "123.46M"},
   2784   {1.23456789E9, "1.2346B"},
   2785   {1.23456789E10, "12.346B"},
   2786   {1.23456789E11, "123.46B"},
   2787   {1.23456789E12, "1.2346T"},
   2788   {1.23456789E13, "12.346T"},
   2789   {1.23456789E14, "123.46T"},
   2790   {1.23456789E15, "1234.6T"},
   2791   {0.0, NULL}
   2792 };
   2793 
   2794 static const ValueAndExpectedString enShortMin3[] = {
   2795   {0.0, "0.00"},
   2796   {0.17, "0.170"},
   2797   {1.0, "1.00"},
   2798   {1234.0, "1.23K"},
   2799   {12345.0, "12.3K"},
   2800   {123456.0, "123K"},
   2801   {1234567.0, "1.23M"},
   2802   {12345678.0, "12.3M"},
   2803   {123456789.0, "123M"},
   2804   {1.23456789E9, "1.23B"},
   2805   {1.23456789E10, "12.3B"},
   2806   {1.23456789E11, "123B"},
   2807   {1.23456789E12, "1.23T"},
   2808   {1.23456789E13, "12.3T"},
   2809   {1.23456789E14, "123T"},
   2810   {1.23456789E15, "1230T"},
   2811   {0.0, NULL}
   2812 };
   2813 
   2814 static const ValueAndExpectedString jaShortMax2[] = {
   2815   {1234.0, "1200"},
   2816   {12345.0, "1.2\\u4E07"},
   2817   {123456.0, "12\\u4E07"},
   2818   {1234567.0, "120\\u4E07"},
   2819   {12345678.0, "1200\\u4E07"},
   2820   {123456789.0, "1.2\\u5104"},
   2821   {1.23456789E9, "12\\u5104"},
   2822   {1.23456789E10, "120\\u5104"},
   2823   {1.23456789E11, "1200\\u5104"},
   2824   {1.23456789E12, "1.2\\u5146"},
   2825   {1.23456789E13, "12\\u5146"},
   2826   {1.23456789E14, "120\\u5146"},
   2827   {0.0, NULL}
   2828 };
   2829 
   2830 static const ValueAndExpectedString srLongMax2[] = {
   2831   {1234.0, "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
   2832   {12345.0, "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
   2833   {21789.0, "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
   2834   {123456.0, "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
   2835   {999999.0, "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
   2836   {1234567.0, "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
   2837   {12345678.0, "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
   2838   {123456789.0, "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
   2839   {1.23456789E9, "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
   2840   {1.23456789E10, "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
   2841   {2.08901234E10, "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
   2842   {2.18901234E10, "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
   2843   {1.23456789E11, "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
   2844   {-1234.0, "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
   2845   {-12345.0, "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
   2846   {-21789.0, "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
   2847   {-123456.0, "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
   2848   {-999999.0, "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
   2849   {-1234567.0, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
   2850   {-12345678.0, "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
   2851   {-123456789.0, "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
   2852   {-1.23456789E9, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
   2853   {-1.23456789E10, "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
   2854   {-2.08901234E10, "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
   2855   {-2.18901234E10, "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
   2856   {-1.23456789E11, "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
   2857   {0.0, NULL}
   2858 };
   2859 
   2860 typedef struct {
   2861     const char *       locale;
   2862     UNumberFormatStyle style;
   2863     int32_t            attribute; // UNumberFormatAttribute, or -1 for none
   2864     int32_t            attrValue; //
   2865     const ValueAndExpectedString * veItems;
   2866 } LocStyleAttributeTest;
   2867 
   2868 static const LocStyleAttributeTest lsaTests[] = {
   2869   { "en",   UNUM_DECIMAL_COMPACT_SHORT,     -1,                             0,  enShort },
   2870   { "en",   UNUM_DECIMAL_COMPACT_SHORT,     UNUM_MAX_SIGNIFICANT_DIGITS,    2,  enShortMax2 },
   2871   { "en",   UNUM_DECIMAL_COMPACT_SHORT,     UNUM_MAX_SIGNIFICANT_DIGITS,    5,  enShortMax5 },
   2872   { "en",   UNUM_DECIMAL_COMPACT_SHORT,     UNUM_MIN_SIGNIFICANT_DIGITS,    3,  enShortMin3 },
   2873   { "ja",   UNUM_DECIMAL_COMPACT_SHORT,     UNUM_MAX_SIGNIFICANT_DIGITS,    2,  jaShortMax2 },
   2874   { "sr",   UNUM_DECIMAL_COMPACT_LONG,      UNUM_MAX_SIGNIFICANT_DIGITS,    2,  srLongMax2  },
   2875   { NULL,   (UNumberFormatStyle)0,          -1,                             0,  NULL }
   2876 };
   2877 
   2878 static void TestVariousStylesAndAttributes(void) {
   2879     const LocStyleAttributeTest * lsaTestPtr;
   2880     for (lsaTestPtr = lsaTests; lsaTestPtr->locale != NULL; lsaTestPtr++) {
   2881         UErrorCode status = U_ZERO_ERROR;
   2882         UNumberFormat * unum = unum_open(lsaTestPtr->style, NULL, 0, lsaTestPtr->locale, NULL, &status);
   2883         if ( U_FAILURE(status) ) {
   2884             log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr->style, lsaTestPtr->locale, u_errorName(status));
   2885         } else {
   2886             const ValueAndExpectedString * veItemPtr;
   2887             if (lsaTestPtr->attribute >= 0) {
   2888                 unum_setAttribute(unum, (UNumberFormatAttribute)lsaTestPtr->attribute, lsaTestPtr->attrValue);
   2889             }
   2890             for (veItemPtr = lsaTestPtr->veItems; veItemPtr->expected != NULL; veItemPtr++) {
   2891                 UChar uexp[kUBufSize];
   2892                 UChar uget[kUBufSize];
   2893                 int32_t uexplen, ugetlen;
   2894 
   2895                 status = U_ZERO_ERROR;
   2896                 uexplen = u_unescape(veItemPtr->expected, uexp, kUBufSize);
   2897                 ugetlen = unum_formatDouble(unum, veItemPtr->value, uget, kUBufSize, NULL, &status);
   2898                 if ( U_FAILURE(status) ) {
   2899                     log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n",
   2900                             (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, u_errorName(status));
   2901                 } else if (ugetlen != uexplen || u_strncmp(uget, uexp, uexplen) != 0) {
   2902                     char bexp[kBBufSize];
   2903                     char bget[kBBufSize];
   2904                     u_strToUTF8(bexp, kBBufSize, NULL, uexp, uexplen, &status);
   2905                     u_strToUTF8(bget, kBBufSize, NULL, uget, ugetlen, &status);
   2906                     log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n",
   2907                             (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, bexp, bget);
   2908                 }
   2909             }
   2910             unum_close(unum);
   2911         }
   2912     }
   2913 }
   2914 
   2915 static const UChar currpat[]  = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
   2916 static const UChar parsetxt[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */
   2917 
   2918 static void TestParseCurrPatternWithDecStyle() {
   2919     UErrorCode status = U_ZERO_ERROR;
   2920     UNumberFormat *unumfmt = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
   2921     if (U_FAILURE(status)) {
   2922         log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status));
   2923     } else {
   2924         unum_applyPattern(unumfmt, FALSE, currpat, -1, NULL, &status);
   2925         if (U_FAILURE(status)) {
   2926             log_err_status(status, "unum_applyPattern failed: %s\n", u_errorName(status));
   2927         } else {
   2928             int32_t pos = 0;
   2929             double value = unum_parseDouble(unumfmt, parsetxt, -1, &pos, &status);
   2930             if (U_SUCCESS(status)) {
   2931                 log_err_status(status, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status), value);
   2932             }
   2933         }
   2934         unum_close(unumfmt);
   2935     }
   2936 }
   2937 
   2938 /*
   2939  * Ticket #12684
   2940  * Test unum_formatDoubleForFields (and UFieldPositionIterator)
   2941  */
   2942 
   2943 typedef struct {
   2944     int32_t field;
   2945     int32_t beginPos;
   2946     int32_t endPos;
   2947 } FieldsData;
   2948 
   2949 typedef struct {
   2950     const char *       locale;
   2951     UNumberFormatStyle style;
   2952     double             value;
   2953     const FieldsData * expectedFields;
   2954 } FormatForFieldsItem;
   2955 
   2956 static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
   2957 
   2958 
   2959 /* "en_US", UNUM_CURRENCY, 123456.0 : "#,##0.00" => "$123,456.00" */
   2960 static const FieldsData fields_en_CURR[] = {
   2961     { UNUM_CURRENCY_FIELD /*7*/,            0, 1 },
   2962     { UNUM_GROUPING_SEPARATOR_FIELD /*6*/,  4, 5 },
   2963     { UNUM_INTEGER_FIELD /*0*/,             1, 8 },
   2964     { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/,   8, 9 },
   2965     { UNUM_FRACTION_FIELD /*1*/,            9, 11 },
   2966     { -1, -1, -1 },
   2967 };
   2968 /* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
   2969 static const FieldsData fields_en_PRCT[] = {
   2970     { UNUM_SIGN_FIELD /*10*/,               0, 1 },
   2971     { UNUM_INTEGER_FIELD /*0*/,             1, 3 },
   2972     { UNUM_PERCENT_FIELD /*8*/,             3, 4 },
   2973     { -1, -1, -1 },
   2974 };
   2975 /* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00" => "123,456.00 " */
   2976 static const FieldsData fields_fr_CURR[] = {
   2977     { UNUM_GROUPING_SEPARATOR_FIELD /*6*/,  3, 4 },
   2978     { UNUM_INTEGER_FIELD /*0*/,             0, 7 },
   2979     { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/,   7, 8 },
   2980     { UNUM_FRACTION_FIELD /*1*/,            8, 10 },
   2981     { UNUM_CURRENCY_FIELD /*7*/,           11, 12 },
   2982     { -1, -1, -1 },
   2983 };
   2984 /* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
   2985 static const FieldsData fields_en_PATN[] = {
   2986     { UNUM_INTEGER_FIELD /*0*/,             1, 3 },
   2987     { -1, -1, -1 },
   2988 };
   2989 
   2990 static const FormatForFieldsItem fffItems[] = {
   2991     { "en_US", UNUM_CURRENCY_STANDARD, 123456.0, fields_en_CURR },
   2992     { "en_US", UNUM_PERCENT,              -0.34, fields_en_PRCT },
   2993     { "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR },
   2994     { "en_US", UNUM_PATTERN_DECIMAL,       12.0, fields_en_PATN },
   2995     { NULL, (UNumberFormatStyle)0, 0, NULL },
   2996 };
   2997 
   2998 static void TestFormatForFields(void) {
   2999     UErrorCode status = U_ZERO_ERROR;
   3000     UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
   3001     if ( U_FAILURE(status) ) {
   3002         log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
   3003     } else {
   3004         const FormatForFieldsItem * itemPtr;
   3005         for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) {
   3006             UNumberFormat* unum;
   3007             status = U_ZERO_ERROR;
   3008             unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)?
   3009                 unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status):
   3010                 unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
   3011             if ( U_FAILURE(status) ) {
   3012                 log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr->locale, itemPtr->style, u_errorName(status));
   3013             } else {
   3014                 UChar ubuf[kUBufSize];
   3015                 int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status);
   3016                 if ( U_FAILURE(status) ) {
   3017                     log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
   3018                 } else {
   3019                     const FieldsData * fptr;
   3020                     int32_t field, beginPos, endPos;
   3021                     for (fptr = itemPtr->expectedFields; TRUE; fptr++) {
   3022                         field = ufieldpositer_next(fpositer, &beginPos, &endPos);
   3023                         if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
   3024                             if (fptr->field >= 0) {
   3025                                 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
   3026                                     itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
   3027                             } else {
   3028                                 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
   3029                                     itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos);
   3030                             }
   3031                             break;
   3032                         }
   3033                         if (field < 0) {
   3034                             break;
   3035                         }
   3036                     }
   3037                 }
   3038                 unum_close(unum);
   3039             }
   3040         }
   3041         ufieldpositer_close(fpositer);
   3042     }
   3043 }
   3044 
   3045 #endif /* #if !UCONFIG_NO_FORMATTING */
   3046