1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2013, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6/********************************************************************************
7*
8* File CNUMTST.C
9*
10*     Madhu Katragadda              Creation
11*
12* Modification History:
13*
14*   Date        Name        Description
15*   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
16*   07/15/99    helena      Ported to HPUX 10/11 CC.
17*********************************************************************************
18*/
19
20/* C API TEST FOR NUMBER FORMAT */
21
22#include "unicode/utypes.h"
23
24#if !UCONFIG_NO_FORMATTING
25
26#include "unicode/uloc.h"
27#include "unicode/umisc.h"
28#include "unicode/unum.h"
29#include "unicode/unumsys.h"
30#include "unicode/ustring.h"
31
32#include "cintltst.h"
33#include "cnumtst.h"
34#include "cmemory.h"
35#include "cstring.h"
36#include "putilimp.h"
37#include <stdio.h>
38
39#define LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
40
41static const char *tagAssert(const char *f, int32_t l, const char *msg) {
42    static char _fileline[1000];
43    sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg);
44    return _fileline;
45}
46
47#define ASSERT_TRUE(x)   assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
48
49void addNumForTest(TestNode** root);
50static void TestTextAttributeCrash(void);
51static void TestNBSPInPattern(void);
52static void TestInt64Parse(void);
53static void TestParseCurrency(void);
54static void TestMaxInt(void);
55static void TestNoExponent(void);
56static void TestUFormattable(void);
57static void TestUNumberingSystem(void);
58
59#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
60
61void addNumForTest(TestNode** root)
62{
63    TESTCASE(TestNumberFormat);
64    TESTCASE(TestSpelloutNumberParse);
65    TESTCASE(TestSignificantDigits);
66    TESTCASE(TestSigDigRounding);
67    TESTCASE(TestNumberFormatPadding);
68    TESTCASE(TestInt64Format);
69    TESTCASE(TestNonExistentCurrency);
70    TESTCASE(TestCurrencyRegression);
71    TESTCASE(TestTextAttributeCrash);
72    TESTCASE(TestRBNFFormat);
73    TESTCASE(TestNBSPInPattern);
74    TESTCASE(TestInt64Parse);
75    TESTCASE(TestParseZero);
76    TESTCASE(TestParseCurrency);
77    TESTCASE(TestCloneWithRBNF);
78    TESTCASE(TestMaxInt);
79    TESTCASE(TestNoExponent);
80    TESTCASE(TestUFormattable);
81    TESTCASE(TestUNumberingSystem);
82}
83
84/* test Parse int 64 */
85
86static void TestInt64Parse()
87{
88
89    UErrorCode st = U_ZERO_ERROR;
90    UErrorCode* status = &st;
91
92    const char* st1 = "009223372036854775808";
93    const int size = 21;
94    UChar text[21];
95
96
97    UNumberFormat* nf;
98
99    int64_t a;
100
101    u_charsToUChars(st1, text, size);
102    nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status);
103
104    if(U_FAILURE(*status))
105    {
106        log_data_err("Error in unum_open() %s \n", myErrorName(*status));
107        return;
108    }
109
110    log_verbose("About to test unum_parseInt64() with out of range number\n");
111
112    a = unum_parseInt64(nf, text, size, 0, status);
113    (void)a;     /* Suppress set but not used warning. */
114
115
116    if(!U_FAILURE(*status))
117    {
118        log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status));
119    }
120    else
121    {
122        log_verbose("unum_parseInt64() successful\n");
123    }
124
125    unum_close(nf);
126    return;
127}
128
129/* test Number Format API */
130static void TestNumberFormat()
131{
132    UChar *result=NULL;
133    UChar temp1[512];
134    UChar temp2[512];
135
136    UChar temp[5];
137
138    UChar prefix[5];
139    UChar suffix[5];
140    UChar symbol[20];
141    int32_t resultlength;
142    int32_t resultlengthneeded;
143    int32_t parsepos;
144    double d1 = -1.0;
145    int32_t l1;
146    double d = -10456.37;
147    double a = 1234.56, a1 = 1235.0;
148    int32_t l = 100000000;
149    UFieldPosition pos1;
150    UFieldPosition pos2;
151    int32_t numlocales;
152    int32_t i;
153
154    UNumberFormatAttribute attr;
155    UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL;
156    int32_t newvalue;
157    UErrorCode status=U_ZERO_ERROR;
158    UNumberFormatStyle style= UNUM_DEFAULT;
159    UNumberFormat *pattern;
160    UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr,
161                  *cur_frpattern, *myclone, *spellout_def;
162
163    /* Testing unum_open() with various Numberformat styles and locales*/
164    status = U_ZERO_ERROR;
165    log_verbose("Testing  unum_open() with default style and locale\n");
166    def=unum_open(style, NULL,0,NULL, NULL,&status);
167
168    /* Might as well pack it in now if we can't even get a default NumberFormat... */
169    if(U_FAILURE(status))
170    {
171        log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
172        return;
173    }
174
175    log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
176    fr=unum_open(style,NULL,0, "fr_FR",NULL, &status);
177    if(U_FAILURE(status))
178        log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status));
179
180    log_verbose("\nTesting unum_open(currency,NULL,status)\n");
181    style=UNUM_CURRENCY;
182    /* Can't hardcode the result to assume the default locale is "en_US". */
183    cur_def=unum_open(style, NULL,0,"en_US", NULL, &status);
184    if(U_FAILURE(status))
185        log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
186                        myErrorName(status) );
187
188    log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
189    cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status);
190    if(U_FAILURE(status))
191        log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
192                myErrorName(status));
193
194    log_verbose("\nTesting unum_open(percent, NULL, status)\n");
195    style=UNUM_PERCENT;
196    per_def=unum_open(style,NULL,0, NULL,NULL, &status);
197    if(U_FAILURE(status))
198        log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status));
199
200    log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
201    per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status);
202    if(U_FAILURE(status))
203        log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status));
204
205    log_verbose("\nTesting unum_open(spellout, NULL, status)");
206    style=UNUM_SPELLOUT;
207    spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status);
208    if(U_FAILURE(status))
209        log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status));
210
211    /* Testing unum_clone(..) */
212    log_verbose("\nTesting unum_clone(fmt, status)");
213    status = U_ZERO_ERROR;
214    myclone = unum_clone(def,&status);
215    if(U_FAILURE(status))
216        log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status));
217    else
218    {
219        log_verbose("unum_clone() successful\n");
220    }
221
222    /*Testing unum_getAvailable() and unum_countAvailable()*/
223    log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
224    numlocales=unum_countAvailable();
225    if(numlocales < 0)
226        log_err("error in countAvailable");
227    else{
228        log_verbose("unum_countAvialable() successful\n");
229        log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales);
230    }
231    for(i=0;i<numlocales;i++)
232    {
233        log_verbose("%s\n", unum_getAvailable(i));
234        if (unum_getAvailable(i) == 0)
235            log_err("No locale for which number formatting patterns are applicable\n");
236        else
237            log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i));
238    }
239
240
241    /*Testing unum_format() and unum_formatdouble()*/
242    u_uastrcpy(temp1, "$100,000,000.00");
243
244    log_verbose("\nTesting unum_format() \n");
245    resultlength=0;
246    pos1.field = UNUM_INTEGER_FIELD;
247    resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
248    if(status==U_BUFFER_OVERFLOW_ERROR)
249    {
250        status=U_ZERO_ERROR;
251        resultlength=resultlengthneeded+1;
252        result=(UChar*)malloc(sizeof(UChar) * resultlength);
253/*        for (i = 0; i < 100000; i++) */
254        {
255            unum_format(cur_def, l, result, resultlength, &pos1, &status);
256        }
257    }
258
259    if(U_FAILURE(status))
260    {
261        log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) );
262    }
263    if(u_strcmp(result, temp1)==0)
264        log_verbose("Pass: Number formatting using unum_format() successful\n");
265    else
266        log_err("Fail: Error in number Formatting using unum_format()\n");
267    if(pos1.beginIndex == 1 && pos1.endIndex == 12)
268        log_verbose("Pass: Complete number formatting using unum_format() successful\n");
269    else
270        log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
271                pos1.beginIndex, pos1.endIndex);
272
273    free(result);
274    result = 0;
275
276    log_verbose("\nTesting unum_formatDouble()\n");
277    u_uastrcpy(temp1, "-$10,456.37");
278    resultlength=0;
279    pos2.field = UNUM_FRACTION_FIELD;
280    resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status);
281    if(status==U_BUFFER_OVERFLOW_ERROR)
282    {
283        status=U_ZERO_ERROR;
284        resultlength=resultlengthneeded+1;
285        result=(UChar*)malloc(sizeof(UChar) * resultlength);
286/*        for (i = 0; i < 100000; i++) */
287        {
288            unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status);
289        }
290    }
291    if(U_FAILURE(status))
292    {
293        log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
294    }
295    if(result && u_strcmp(result, temp1)==0)
296        log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
297    else {
298      log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
299              aescstrdup(result, -1), aescstrdup(temp1, -1));
300    }
301    if(pos2.beginIndex == 9 && pos2.endIndex == 11)
302        log_verbose("Pass: Complete number formatting using unum_format() successful\n");
303    else
304        log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
305                pos1.beginIndex, pos1.endIndex);
306
307
308    /* Testing unum_parse() and unum_parseDouble() */
309    log_verbose("\nTesting unum_parseDouble()\n");
310/*    for (i = 0; i < 100000; i++)*/
311    parsepos=0;
312    if (result != NULL) {
313      d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status);
314    } else {
315      log_err("result is NULL\n");
316    }
317    if(U_FAILURE(status)) {
318      log_err("parse of '%s' failed. Parsepos=%d. The error is  : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status));
319    }
320
321    if(d1!=d)
322        log_err("Fail: Error in parsing\n");
323    else
324        log_verbose("Pass: parsing successful\n");
325    if (result)
326        free(result);
327    result = 0;
328
329    status = U_ZERO_ERROR;
330    /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
331    log_verbose("\nTesting unum_formatDoubleCurrency\n");
332    u_uastrcpy(temp1, "Y1,235");
333    temp1[0] = 0xA5; /* Yen sign */
334    u_uastrcpy(temp, "JPY");
335    resultlength=0;
336    pos2.field = UNUM_INTEGER_FIELD;
337    resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status);
338    if (status==U_BUFFER_OVERFLOW_ERROR) {
339        status=U_ZERO_ERROR;
340        resultlength=resultlengthneeded+1;
341        result=(UChar*)malloc(sizeof(UChar) * resultlength);
342        unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status);
343    }
344    if (U_FAILURE(status)) {
345        log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
346    }
347    if (result && u_strcmp(result, temp1)==0) {
348        log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
349    } else {
350        log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
351                aescstrdup(result, -1), aescstrdup(temp1, -1));
352    }
353    if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
354        log_verbose("Pass: Complete number formatting using unum_format() successful\n");
355    } else {
356        log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
357                pos1.beginIndex, pos1.endIndex);
358    }
359
360    log_verbose("\nTesting unum_parseDoubleCurrency\n");
361    parsepos=0;
362    if (result == NULL) {
363        log_err("result is NULL\n");
364    }
365    else {
366        d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
367        if (U_FAILURE(status)) {
368          log_err("parseDoubleCurrency '%s' failed. The error is  : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
369        }
370        /* Note: a==1234.56, but on parse expect a1=1235.0 */
371        if (d1!=a1) {
372            log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1);
373        } else {
374            log_verbose("Pass: parsed currency amount successfully\n");
375        }
376        if (u_strcmp(temp2, temp)==0) {
377            log_verbose("Pass: parsed correct currency\n");
378        } else {
379            log_err("Fail: parsed incorrect currency\n");
380        }
381    }
382    status = U_ZERO_ERROR; /* reset */
383
384    free(result);
385    result = 0;
386
387
388/* performance testing */
389    u_uastrcpy(temp1, "$462.12345");
390    resultlength=u_strlen(temp1);
391/*    for (i = 0; i < 100000; i++) */
392    {
393        parsepos=0;
394        d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status);
395    }
396    if(U_FAILURE(status))
397    {
398        log_err("parseDouble('%s') failed. The error is  : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
399    }
400
401    /*
402     * Note: "for strict standard conformance all operations and constants are now supposed to be
403              evaluated in precision of long double".  So,  we assign a1 before comparing to a double. Bug #7932.
404     */
405    a1 = 462.12345;
406
407    if(d1!=a1)
408        log_err("Fail: Error in parsing\n");
409    else
410        log_verbose("Pass: parsing successful\n");
411
412free(result);
413
414    u_uastrcpy(temp1, "($10,456.3E1])");
415    parsepos=0;
416    d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status);
417    if(U_SUCCESS(status))
418    {
419        log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status));
420    }
421
422
423    log_verbose("\nTesting unum_format()\n");
424    status=U_ZERO_ERROR;
425    resultlength=0;
426    parsepos=0;
427    resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status);
428    if(status==U_BUFFER_OVERFLOW_ERROR)
429    {
430        status=U_ZERO_ERROR;
431        resultlength=resultlengthneeded+1;
432        result=(UChar*)malloc(sizeof(UChar) * resultlength);
433/*        for (i = 0; i < 100000; i++)*/
434        {
435            unum_format(per_fr, l, result, resultlength, &pos1, &status);
436        }
437    }
438    if(U_FAILURE(status))
439    {
440        log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
441    }
442
443
444    log_verbose("\nTesting unum_parse()\n");
445/*    for (i = 0; i < 100000; i++) */
446    {
447        parsepos=0;
448        l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status);
449    }
450    if(U_FAILURE(status))
451    {
452        log_err("parse failed. The error is  : %s\n", myErrorName(status));
453    }
454
455    if(l1!=l)
456        log_err("Fail: Error in parsing\n");
457    else
458        log_verbose("Pass: parsing successful\n");
459
460free(result);
461
462    /* create a number format using unum_openPattern(....)*/
463    log_verbose("\nTesting unum_openPattern()\n");
464    u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)");
465    pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
466    if(U_FAILURE(status))
467    {
468        log_err("error in unum_openPattern(): %s\n", myErrorName(status) );;
469    }
470    else
471        log_verbose("Pass: unum_openPattern() works fine\n");
472
473    /*test for unum_toPattern()*/
474    log_verbose("\nTesting unum_toPattern()\n");
475    resultlength=0;
476    resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
477    if(status==U_BUFFER_OVERFLOW_ERROR)
478    {
479        status=U_ZERO_ERROR;
480        resultlength=resultlengthneeded+1;
481        result=(UChar*)malloc(sizeof(UChar) * resultlength);
482        unum_toPattern(pattern, FALSE, result, resultlength, &status);
483    }
484    if(U_FAILURE(status))
485    {
486        log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
487    }
488    else
489    {
490        if(u_strcmp(result, temp1)!=0)
491            log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
492        else
493            log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
494free(result);
495    }
496
497    /*Testing unum_getSymbols() and unum_setSymbols()*/
498    log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
499    /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
500    resultlength=0;
501    resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status);
502    if(status==U_BUFFER_OVERFLOW_ERROR)
503    {
504        status=U_ZERO_ERROR;
505        resultlength=resultlengthneeded+1;
506        result=(UChar*)malloc(sizeof(UChar) * resultlength);
507        unum_toPattern(cur_def, FALSE, result, resultlength, &status);
508    }
509    if(U_FAILURE(status))
510    {
511        log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
512    }
513
514    status=U_ZERO_ERROR;
515    cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status);
516    if(U_FAILURE(status))
517    {
518        log_err("error in unum_openPattern(): %s\n", myErrorName(status));
519    }
520
521free(result);
522
523    /*getting the symbols of cur_def */
524    /*set the symbols of cur_frpattern to cur_def */
525    for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
526        status=U_ZERO_ERROR;
527        unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
528        unum_setSymbol(cur_frpattern, symType, temp1, -1, &status);
529        if(U_FAILURE(status))
530        {
531            log_err("Error in get/set symbols: %s\n", myErrorName(status));
532        }
533    }
534
535    /*format to check the result */
536    resultlength=0;
537    resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
538    if(status==U_BUFFER_OVERFLOW_ERROR)
539    {
540        status=U_ZERO_ERROR;
541        resultlength=resultlengthneeded+1;
542        result=(UChar*)malloc(sizeof(UChar) * resultlength);
543        unum_format(cur_def, l, result, resultlength, &pos1, &status);
544    }
545    if(U_FAILURE(status))
546    {
547        log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
548    }
549
550    if(U_FAILURE(status)){
551        log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status));
552    }
553    unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL);
554
555    for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
556        status=U_ZERO_ERROR;
557        unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
558        unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status);
559        if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0)
560        {
561            log_err("Fail: error in getting symbols\n");
562        }
563        else
564            log_verbose("Pass: get and set symbols successful\n");
565    }
566
567    /*format and check with the previous result */
568
569    resultlength=0;
570    resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status);
571    if(status==U_BUFFER_OVERFLOW_ERROR)
572    {
573        status=U_ZERO_ERROR;
574        resultlength=resultlengthneeded+1;
575        unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status);
576    }
577    if(U_FAILURE(status))
578    {
579        log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
580    }
581    /* TODO:
582     * This test fails because we have not called unum_applyPattern().
583     * Currently, such an applyPattern() does not exist on the C API, and
584     * we have jitterbug 411 for it.
585     * Since it is close to the 1.5 release, I (markus) am disabling this test just
586     * for this release (I added the test itself only last week).
587     * For the next release, we need to fix this.
588     * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
589     */
590    if(u_strcmp(result, temp1) != 0) {
591        log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1);
592    }
593
594
595    /*----------- */
596
597free(result);
598
599    /* Testing unum_get/setSymbol() */
600    for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
601        symbol[0] = (UChar)(0x41 + i);
602        symbol[1] = (UChar)(0x61 + i);
603        unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status);
604        if(U_FAILURE(status)) {
605            log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status));
606            return;
607        }
608    }
609    for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
610        resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status);
611        if(U_FAILURE(status)) {
612            log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status));
613            return;
614        }
615        if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) {
616            log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i);
617        }
618    }
619    /*try getting from a bogus symbol*/
620    unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status);
621    if(U_SUCCESS(status)){
622        log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
623    }
624    if(U_FAILURE(status)){
625        if(status != U_ILLEGAL_ARGUMENT_ERROR){
626            log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status));
627        }
628    }
629    status=U_ZERO_ERROR;
630
631    /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
632    log_verbose("\nTesting getting and setting text attributes\n");
633    resultlength=5;
634    unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
635    if(U_FAILURE(status))
636    {
637        log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
638    }
639    unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
640    if(U_FAILURE(status))
641    {
642        log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
643    }
644    unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status);
645    if(U_FAILURE(status))
646    {
647        log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
648    }
649    if(u_strcmp(suffix,temp)!=0)
650        log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
651    else
652        log_verbose("Pass: setting and getting suffix works fine\n");
653    /*set it back to normal */
654    u_uastrcpy(temp,"$");
655    unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
656
657    /*checking some more text setter conditions */
658    u_uastrcpy(prefix, "+");
659    unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status);
660    if(U_FAILURE(status))
661    {
662        log_err("error in setting the text attributes : %s\n", myErrorName(status));
663    }
664    unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status);
665    if(U_FAILURE(status))
666    {
667        log_err("error in getting the text attributes : %s\n", myErrorName(status));
668    }
669
670    if(u_strcmp(prefix, temp)!=0)
671        log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
672    else
673        log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
674
675    u_uastrcpy(prefix, "+");
676    unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status);
677    if(U_FAILURE(status))
678    {
679        log_err("error in setting the text attributes : %s\n", myErrorName(status));
680    }
681    unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status);
682    if(U_FAILURE(status))
683    {
684        log_err("error in getting the text attributes : %s\n", myErrorName(status));
685    }
686    if(u_strcmp(prefix, temp)!=0)
687        log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
688    else
689        log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
690
691    u_uastrcpy(suffix, "+");
692    unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
693    if(U_FAILURE(status))
694    {
695        log_err("error in setting the text attributes: %s\n", myErrorName(status));
696    }
697
698    unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
699    if(U_FAILURE(status))
700    {
701        log_err("error in getting the text attributes : %s\n", myErrorName(status));
702    }
703    if(u_strcmp(suffix, temp)!=0)
704        log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
705    else
706        log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
707
708    u_uastrcpy(suffix, "++");
709    unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
710    if(U_FAILURE(status))
711    {
712        log_err("error in setting the text attributes: %s\n", myErrorName(status));
713    }
714
715    unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status);
716    if(U_FAILURE(status))
717    {
718        log_err("error in getting the text attributes : %s\n", myErrorName(status));
719    }
720    if(u_strcmp(suffix, temp)!=0)
721        log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
722    else
723        log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
724
725    /*Testing unum_getAttribute and  unum_setAttribute() */
726    log_verbose("\nTesting get and set Attributes\n");
727    attr=UNUM_GROUPING_SIZE;
728    newvalue=unum_getAttribute(def, attr);
729    newvalue=2;
730    unum_setAttribute(def, attr, newvalue);
731    if(unum_getAttribute(def,attr)!=2)
732        log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
733    else
734        log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
735
736    attr=UNUM_MULTIPLIER;
737    newvalue=unum_getAttribute(def, attr);
738    newvalue=8;
739    unum_setAttribute(def, attr, newvalue);
740    if(unum_getAttribute(def,attr) != 8)
741        log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
742    else
743        log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
744
745    attr=UNUM_SECONDARY_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("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
751    else
752        log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
753
754    /*testing set and get Attributes extensively */
755    log_verbose("\nTesting get and set attributes extensively\n");
756    for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) )
757    {
758        newvalue=unum_getAttribute(fr, attr);
759        unum_setAttribute(def, attr, newvalue);
760        if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr))
761            log_err("error in setting and getting attributes\n");
762        else
763            log_verbose("Pass: attributes set and retrieved successfully\n");
764    }
765
766    /*testing spellout format to make sure we can use it successfully.*/
767    log_verbose("\nTesting spellout format\n");
768    if (spellout_def)
769    {
770        static const int32_t values[] = { 0, -5, 105, 1005, 105050 };
771        for (i = 0; i < LENGTH(values); ++i) {
772            UChar buffer[128];
773            int32_t len;
774            int32_t value = values[i];
775            status = U_ZERO_ERROR;
776            len = unum_format(spellout_def, value, buffer, LENGTH(buffer), NULL, &status);
777            if(U_FAILURE(status)) {
778                log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
779            } else {
780                int32_t pp = 0;
781                int32_t parseResult;
782                /*ustrToAstr(buffer, len, logbuf, LENGTH(logbuf));*/
783                log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
784
785                parseResult = unum_parse(spellout_def, buffer, len, &pp, &status);
786                if (U_FAILURE(status)) {
787                    log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
788                } else if (parseResult != value) {
789                    log_err("unum_format result %d != value %d\n", parseResult, value);
790                }
791            }
792        }
793    }
794    else {
795        log_err("Spellout format is unavailable\n");
796    }
797
798    {    /* Test for ticket #7079 */
799        UNumberFormat* dec_en;
800        UChar groupingSep[] = { 0 };
801        UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
802        double parseResult = 0.0;
803
804        status=U_ZERO_ERROR;
805        dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
806        unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0);
807        unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status);
808        parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status);
809        /* Without the fix in #7079, the above call will hang */
810        if ( U_FAILURE(status) || parseResult != 12.0 ) {
811            log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
812                    myErrorName(status), parseResult);
813        } else {
814            log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
815        }
816        unum_close(dec_en);
817    }
818
819    {   /* Test parse & format of big decimals.  Use a number with too many digits to fit in a double,
820                                         to verify that it is taking the pure decimal path. */
821        UNumberFormat *fmt;
822        const char *bdpattern = "#,##0.#########";
823        const char *numInitial     = "12345678900987654321.1234567896";
824        const char *numFormatted  = "12,345,678,900,987,654,321.12345679";
825        const char *parseExpected = "12345678900987654321.12345679";
826        int32_t resultSize    = 0;
827        int32_t parsePos      = 0;     /* Output parameter for Parse operations. */
828        #define DESTCAPACITY 100
829        UChar dest[DESTCAPACITY];
830        char  desta[DESTCAPACITY];
831        UFieldPosition fieldPos = {0};
832
833        /* Format */
834
835        status = U_ZERO_ERROR;
836        u_uastrcpy(dest, bdpattern);
837        fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status);
838        if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
839
840        resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status);
841        if (U_FAILURE(status)) {
842            log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
843        }
844        u_austrncpy(desta, dest, DESTCAPACITY);
845        if (strcmp(numFormatted, desta) != 0) {
846            log_err("File %s, Line %d, (expected, acutal) =  (\"%s\", \"%s\")\n",
847                    __FILE__, __LINE__, numFormatted, desta);
848        }
849        if (strlen(numFormatted) != resultSize) {
850            log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
851                     __FILE__, __LINE__, strlen(numFormatted), resultSize);
852        }
853
854        /* Format with a FieldPosition parameter */
855
856        fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
857        resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status);
858        if (U_FAILURE(status)) {
859            log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
860        }
861        u_austrncpy(desta, dest, DESTCAPACITY);
862        if (strcmp(numFormatted, desta) != 0) {
863            log_err("File %s, Line %d, (expected, acutal) =  (\"%s\", \"%s\")\n",
864                    __FILE__, __LINE__, numFormatted, desta);
865        }
866        if (fieldPos.beginIndex != 26) {  /* index of "." in formatted number */
867            log_err("File %s, Line %d, (expected, acutal) =  (%d, %d)\n",
868                    __FILE__, __LINE__, 0, fieldPos.beginIndex);
869        }
870        if (fieldPos.endIndex != 27) {
871            log_err("File %s, Line %d, (expected, acutal) =  (%d, %d)\n",
872                    __FILE__, __LINE__, 0, fieldPos.endIndex);
873        }
874
875        /* Parse */
876
877        status = U_ZERO_ERROR;
878        u_uastrcpy(dest, numFormatted);   /* Parse the expected output of the formatting test */
879        resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status);
880        if (U_FAILURE(status)) {
881            log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
882        }
883        if (strcmp(parseExpected, desta) != 0) {
884            log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
885                    __FILE__, __LINE__, parseExpected, desta);
886        }
887        if (strlen(parseExpected) != resultSize) {
888            log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
889                    __FILE__, __LINE__, strlen(parseExpected), resultSize);
890        }
891
892        /* Parse with a parsePos parameter */
893
894        status = U_ZERO_ERROR;
895        u_uastrcpy(dest, numFormatted);   /* Parse the expected output of the formatting test */
896        parsePos = 3;                 /*      12,345,678,900,987,654,321.12345679         */
897                                      /* start parsing at the the third char              */
898        resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status);
899        if (U_FAILURE(status)) {
900            log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
901        }
902        if (strcmp(parseExpected+2, desta) != 0) {   /*  "345678900987654321.12345679" */
903            log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
904                    __FILE__, __LINE__, parseExpected+2, desta);
905        }
906        if (strlen(numFormatted) != parsePos) {
907            log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
908                    __FILE__, __LINE__, strlen(parseExpected), parsePos);
909        }
910
911        unum_close(fmt);
912    }
913
914    status = U_ZERO_ERROR;
915    /* Test invalid symbol argument */
916    {
917        int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1;
918        int32_t badsymbolSmall = -1;
919        UChar value[10];
920        int32_t valueLength = 10;
921        UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
922        if (U_FAILURE(status)) {
923            log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
924        } else {
925            unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status);
926            if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
927
928            status = U_ZERO_ERROR;
929            unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status);
930            if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
931
932            status = U_ZERO_ERROR;
933            unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status);
934            if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
935
936            status = U_ZERO_ERROR;
937            unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status);
938            if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
939
940            unum_close(fmt);
941        }
942    }
943
944
945    /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
946    unum_close(def);
947    unum_close(fr);
948    unum_close(cur_def);
949    unum_close(cur_fr);
950    unum_close(per_def);
951    unum_close(per_fr);
952    unum_close(spellout_def);
953    unum_close(pattern);
954    unum_close(cur_frpattern);
955    unum_close(myclone);
956
957}
958
959static void TestParseZero(void)
960{
961    UErrorCode errorCode = U_ZERO_ERROR;
962    UChar input[] = {0x30, 0};   /*  Input text is decimal '0' */
963    UChar pat[] = {0x0023,0x003b,0x0023,0}; /*  {'#', ';', '#', 0}; */
964    double  dbl;
965
966#if 0
967    UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode);
968#else
969    UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode);
970#endif
971
972    dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode );
973    if (U_FAILURE(errorCode)) {
974        log_data_err("Result - %s\n", u_errorName(errorCode));
975    } else {
976        log_verbose("Double: %f\n", dbl);
977    }
978    unum_close(unum);
979}
980
981static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
982static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */
983static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
984static const UChar pounds3Sym[]  = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
985static const UChar pounds5Sym[]  = { 0xA3,0x35,0 }; /* [POUND]5 */
986static const UChar pounds7Sym[]  = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
987static const UChar euros4Sym[]   = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
988static const UChar euros6Sym[]   = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
989static const UChar euros8Sym[]   = { 0x20AC,0x38,0 }; /* [EURO]8 */
990static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
991static 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 */
992static const UChar euros8PluEn[]   = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
993static const UChar euros6PluFr[]   = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
994
995typedef struct {
996    const char *  locale;
997    const char *  descrip;
998    const UChar * currStr;
999    const UChar * plurStr;
1000    UErrorCode    parsDoubExpectErr;
1001    int32_t       parsDoubExpectPos;
1002    double        parsDoubExpectVal;
1003    UErrorCode    parsCurrExpectErr;
1004    int32_t       parsCurrExpectPos;
1005    double        parsCurrExpectVal;
1006    const char *  parsCurrExpectCurr;
1007} ParseCurrencyItem;
1008
1009static const ParseCurrencyItem parseCurrencyItems[] = {
1010    { "en_US", "dollars2", dollars2Sym, NULL,          U_ZERO_ERROR,  5, 2.0, U_ZERO_ERROR,  5, 2.0, "USD" },
1011    { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR,  2, 4.0, U_ZERO_ERROR,  2, 4.0, "USD" },
1012    { "en_US", "dollars9", dollars9Sym, NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
1013    { "en_US", "pounds3",  pounds3Sym,  NULL,          U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
1014    { "en_US", "pounds5",  pounds5Sym,  pounds5PluEn,  U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
1015    { "en_US", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
1016    { "en_US", "euros8",   euros8Sym,   euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
1017
1018    { "en_GB", "pounds3",  pounds3Sym,  NULL,          U_ZERO_ERROR,  5, 3.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
1019    { "en_GB", "pounds5",  pounds5Sym,  pounds5PluEn,  U_ZERO_ERROR,  2, 5.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
1020    { "en_GB", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
1021    { "en_GB", "euros4",   euros4Sym,   NULL,          U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, ""    },
1022    { "en_GB", "euros6",   euros6Sym,   NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
1023    { "en_GB", "euros8",   euros8Sym,   euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
1024    { "en_GB", "dollars4", dollars4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 4.0, "USD" },
1025
1026    { "fr_FR", "euros4",   euros4Sym,   NULL,          U_ZERO_ERROR,  6, 4.0, U_ZERO_ERROR,  6, 4.0, "EUR" },
1027    { "fr_FR", "euros6",   euros6Sym,   euros6PluFr,   U_ZERO_ERROR,  3, 6.0, U_ZERO_ERROR,  3, 6.0, "EUR" },
1028    { "fr_FR", "euros8",   euros8Sym,   NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
1029    { "fr_FR", "dollars2", dollars2Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
1030    { "fr_FR", "dollars4", dollars4Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
1031
1032    { NULL,    NULL,       NULL,        NULL,          0,             0, 0.0, 0,             0, 0.0, NULL  }
1033};
1034
1035static void TestParseCurrency()
1036{
1037    const ParseCurrencyItem * itemPtr;
1038    for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) {
1039        UNumberFormat* unum;
1040        UErrorCode status;
1041        double parseVal;
1042        int32_t parsePos;
1043        UChar parseCurr[4];
1044        char parseCurrB[4];
1045
1046        status = U_ZERO_ERROR;
1047        unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
1048        if (U_SUCCESS(status)) {
1049            status = U_ZERO_ERROR;
1050            parsePos = 0;
1051            parseVal = unum_parseDouble(unum, itemPtr->currStr, -1, &parsePos, &status);
1052            if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
1053                log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1054                        itemPtr->locale, itemPtr->descrip,
1055                        u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
1056                        u_errorName(status), parsePos, parseVal );
1057            }
1058            status = U_ZERO_ERROR;
1059            parsePos = 0;
1060            parseCurr[0] = 0;
1061            parseVal = unum_parseDoubleCurrency(unum, itemPtr->currStr, -1, &parsePos, parseCurr, &status);
1062            u_austrncpy(parseCurrB, parseCurr, 4);
1063            if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal ||
1064                    strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1065                log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1066                        itemPtr->locale, itemPtr->descrip,
1067                        u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1068                        u_errorName(status), parsePos, parseVal, parseCurrB );
1069            }
1070            unum_close(unum);
1071        } else {
1072            log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1073        }
1074
1075#if 0
1076        /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */
1077        if (itemPtr->plurStr != NULL) {
1078            status = U_ZERO_ERROR;
1079            unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status);
1080            if (U_SUCCESS(status)) {
1081                status = U_ZERO_ERROR;
1082                parsePos = 0;
1083                parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
1084                if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
1085                    log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
1086                            itemPtr->locale, itemPtr->descrip,
1087                            u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
1088                            u_errorName(status), parseVal );
1089                }
1090                status = U_ZERO_ERROR;
1091                parsePos = 0;
1092                parseCurr[0] = 0;
1093                parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status);
1094                u_austrncpy(parseCurrB, parseCurr, 4);
1095                if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal ||
1096                        strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1097                    log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1098                            itemPtr->locale, itemPtr->descrip,
1099                            u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1100                            u_errorName(status), parseVal, parseCurrB );
1101                }
1102                unum_close(unum);
1103            } else {
1104                log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1105            }
1106        }
1107#endif
1108    }
1109}
1110
1111typedef struct {
1112    const char *  testname;
1113    const char *  locale;
1114    const UChar * source;
1115    int32_t       startPos;
1116    int32_t       value;
1117    int32_t       endPos;
1118    UErrorCode    status;
1119} SpelloutParseTest;
1120
1121static const UChar ustr_en0[]   = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1122static const UChar ustr_123[]   = {0x31, 0x32, 0x33, 0};       /* 123 */
1123static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1124                                   0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1125                                   0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1126static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1127                                   0x74, 0x72, 0x6f, 0x69, 0x73, 0};       /* cent vingt-trois */
1128static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0};     /* kanji 100(+)2(*)10(+)3 */
1129
1130static const SpelloutParseTest spelloutParseTests[] = {
1131    /* name    loc   src       start val  end status */
1132    { "en0",   "en", ustr_en0,    0,   0,  4, U_ZERO_ERROR },
1133    { "en0",   "en", ustr_en0,    2,   0,  2, U_PARSE_ERROR },
1134    { "en0",   "ja", ustr_en0,    0,   0,  0, U_PARSE_ERROR },
1135    { "123",   "en", ustr_123,    0, 123,  3, U_ZERO_ERROR },
1136    { "en123", "en", ustr_en123,  0, 123, 24, U_ZERO_ERROR },
1137    { "en123", "en", ustr_en123, 12,  23, 24, U_ZERO_ERROR },
1138    { "en123", "fr", ustr_en123, 16,   0, 16, U_PARSE_ERROR },
1139    { "fr123", "fr", ustr_fr123,  0, 123, 16, U_ZERO_ERROR },
1140    { "fr123", "fr", ustr_fr123,  5,  23, 16, U_ZERO_ERROR },
1141    { "fr123", "en", ustr_fr123,  0,   0,  0, U_PARSE_ERROR },
1142    { "ja123", "ja", ustr_ja123,  0, 123,  4, U_ZERO_ERROR },
1143    { "ja123", "ja", ustr_ja123,  1,  23,  4, U_ZERO_ERROR },
1144    { "ja123", "fr", ustr_ja123,  0,   0,  0, U_PARSE_ERROR },
1145    { NULL,    NULL, NULL,        0,   0,  0, 0 } /* terminator */
1146};
1147
1148static void TestSpelloutNumberParse()
1149{
1150    const SpelloutParseTest * testPtr;
1151    for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
1152        UErrorCode status = U_ZERO_ERROR;
1153        int32_t	value, position = testPtr->startPos;
1154        UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
1155        if (U_FAILURE(status)) {
1156            log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1157            continue;
1158        }
1159        value = unum_parse(nf, testPtr->source, -1, &position, &status);
1160        if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1161            log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1162                    testPtr->locale, testPtr->testname, testPtr->startPos,
1163                    testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1164                    value, position, myErrorName(status) );
1165        }
1166        unum_close(nf);
1167    }
1168}
1169
1170static void TestSignificantDigits()
1171{
1172    UChar temp[128];
1173    int32_t resultlengthneeded;
1174    int32_t resultlength;
1175    UErrorCode status = U_ZERO_ERROR;
1176    UChar *result = NULL;
1177    UNumberFormat* fmt;
1178    double d = 123456.789;
1179
1180    u_uastrcpy(temp, "###0.0#");
1181    fmt=unum_open(UNUM_IGNORE, temp, -1, NULL, NULL,&status);
1182    if (U_FAILURE(status)) {
1183        log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1184        return;
1185    }
1186    unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1187    unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6);
1188
1189    u_uastrcpy(temp, "123457");
1190    resultlength=0;
1191    resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status);
1192    if(status==U_BUFFER_OVERFLOW_ERROR)
1193    {
1194        status=U_ZERO_ERROR;
1195        resultlength=resultlengthneeded+1;
1196        result=(UChar*)malloc(sizeof(UChar) * resultlength);
1197        unum_formatDouble(fmt, d, result, resultlength, NULL, &status);
1198    }
1199    if(U_FAILURE(status))
1200    {
1201        log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1202        return;
1203    }
1204    if(u_strcmp(result, temp)==0)
1205        log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1206    else
1207        log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1208    free(result);
1209    unum_close(fmt);
1210}
1211
1212static void TestSigDigRounding()
1213{
1214    UErrorCode status = U_ZERO_ERROR;
1215    UChar expected[128];
1216    UChar result[128];
1217    char		temp1[128];
1218    char		temp2[128];
1219    UNumberFormat* fmt;
1220    double d = 123.4;
1221
1222    fmt=unum_open(UNUM_DECIMAL, NULL, 0, NULL /* "en_US"*/, NULL, &status);
1223    if (U_FAILURE(status)) {
1224        log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1225        return;
1226    }
1227    unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE);
1228    unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1229    unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2);
1230    /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1231
1232    unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP);
1233    unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0);
1234
1235    (void)unum_formatDouble(fmt, d, result, sizeof(result) / sizeof(result[0]), NULL, &status);
1236    if(U_FAILURE(status))
1237    {
1238        log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1239        return;
1240    }
1241
1242    u_uastrcpy(expected, "140");
1243    if(u_strcmp(result, expected)!=0)
1244        log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) );
1245
1246    unum_close(fmt);
1247}
1248
1249static void TestNumberFormatPadding()
1250{
1251    UChar *result=NULL;
1252    UChar temp1[512];
1253
1254    UErrorCode status=U_ZERO_ERROR;
1255    int32_t resultlength;
1256    int32_t resultlengthneeded;
1257    UNumberFormat *pattern;
1258    double d1;
1259    double d = -10456.37;
1260    UFieldPosition pos1;
1261    int32_t parsepos;
1262
1263    /* create a number format using unum_openPattern(....)*/
1264    log_verbose("\nTesting unum_openPattern() with padding\n");
1265    u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)");
1266    status=U_ZERO_ERROR;
1267    pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
1268    if(U_SUCCESS(status))
1269    {
1270        log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
1271    }
1272    else
1273    {
1274        unum_close(pattern);
1275    }
1276
1277/*    u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1278    u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
1279    status=U_ZERO_ERROR;
1280    pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
1281    if(U_FAILURE(status))
1282    {
1283        log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
1284    }
1285    else {
1286        log_verbose("Pass: padding unum_openPattern() works fine\n");
1287
1288        /*test for unum_toPattern()*/
1289        log_verbose("\nTesting padding unum_toPattern()\n");
1290        resultlength=0;
1291        resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
1292        if(status==U_BUFFER_OVERFLOW_ERROR)
1293        {
1294            status=U_ZERO_ERROR;
1295            resultlength=resultlengthneeded+1;
1296            result=(UChar*)malloc(sizeof(UChar) * resultlength);
1297            unum_toPattern(pattern, FALSE, result, resultlength, &status);
1298        }
1299        if(U_FAILURE(status))
1300        {
1301            log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status));
1302        }
1303        else
1304        {
1305            if(u_strcmp(result, temp1)!=0)
1306                log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
1307            else
1308                log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1309free(result);
1310        }
1311/*        u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1312        u_uastrcpy(temp1, "xxxxx(10,456.37)");
1313        resultlength=0;
1314        pos1.field = UNUM_FRACTION_FIELD;
1315        resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status);
1316        if(status==U_BUFFER_OVERFLOW_ERROR)
1317        {
1318            status=U_ZERO_ERROR;
1319            resultlength=resultlengthneeded+1;
1320            result=(UChar*)malloc(sizeof(UChar) * resultlength);
1321            unum_formatDouble(pattern, d, result, resultlength, NULL, &status);
1322        }
1323        if(U_FAILURE(status))
1324        {
1325            log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status));
1326        }
1327        else
1328        {
1329            if(u_strcmp(result, temp1)==0)
1330                log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1331            else
1332                log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1333            if(pos1.beginIndex == 13 && pos1.endIndex == 15)
1334                log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1335            else
1336                log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1337                        pos1.beginIndex, pos1.endIndex);
1338
1339
1340            /* Testing unum_parse() and unum_parseDouble() */
1341            log_verbose("\nTesting padding unum_parseDouble()\n");
1342            parsepos=0;
1343            d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status);
1344            if(U_FAILURE(status))
1345            {
1346                log_err("padding parse failed. The error is : %s\n", myErrorName(status));
1347            }
1348
1349            if(d1!=d)
1350                log_err("Fail: Error in padding parsing\n");
1351            else
1352                log_verbose("Pass: padding parsing successful\n");
1353free(result);
1354        }
1355    }
1356
1357    unum_close(pattern);
1358}
1359
1360static UBool
1361withinErr(double a, double b, double err) {
1362    return uprv_fabs(a - b) < uprv_fabs(a * err);
1363}
1364
1365static void TestInt64Format() {
1366    UChar temp1[512];
1367    UChar result[512];
1368    UNumberFormat *fmt;
1369    UErrorCode status = U_ZERO_ERROR;
1370    const double doubleInt64Max = (double)U_INT64_MAX;
1371    const double doubleInt64Min = (double)U_INT64_MIN;
1372    const double doubleBig = 10.0 * (double)U_INT64_MAX;
1373    int32_t val32;
1374    int64_t val64;
1375    double  valDouble;
1376    int32_t parsepos;
1377
1378    /* create a number format using unum_openPattern(....) */
1379    log_verbose("\nTesting Int64Format\n");
1380    u_uastrcpy(temp1, "#.#E0");
1381    fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), NULL, NULL, &status);
1382    if(U_FAILURE(status)) {
1383        log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
1384    } else {
1385        unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20);
1386        unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status);
1387        if (U_FAILURE(status)) {
1388            log_err("error in unum_format(): %s\n", myErrorName(status));
1389        } else {
1390            log_verbose("format int64max: '%s'\n", result);
1391            parsepos = 0;
1392            val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1393            if (status != U_INVALID_FORMAT_ERROR) {
1394                log_err("parse didn't report error: %s\n", myErrorName(status));
1395            } else if (val32 != INT32_MAX) {
1396                log_err("parse didn't pin return value, got: %d\n", val32);
1397            }
1398
1399            status = U_ZERO_ERROR;
1400            parsepos = 0;
1401            val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1402            if (U_FAILURE(status)) {
1403                log_err("parseInt64 returned error: %s\n", myErrorName(status));
1404            } else if (val64 != U_INT64_MAX) {
1405                log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1406            }
1407
1408            status = U_ZERO_ERROR;
1409            parsepos = 0;
1410            valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1411            if (U_FAILURE(status)) {
1412                log_err("parseDouble returned error: %s\n", myErrorName(status));
1413            } else if (valDouble != doubleInt64Max) {
1414                log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1415            }
1416        }
1417
1418        unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status);
1419        if (U_FAILURE(status)) {
1420            log_err("error in unum_format(): %s\n", myErrorName(status));
1421        } else {
1422            log_verbose("format int64min: '%s'\n", result);
1423            parsepos = 0;
1424            val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1425            if (status != U_INVALID_FORMAT_ERROR) {
1426                log_err("parse didn't report error: %s\n", myErrorName(status));
1427            } else if (val32 != INT32_MIN) {
1428                log_err("parse didn't pin return value, got: %d\n", val32);
1429            }
1430
1431            status = U_ZERO_ERROR;
1432            parsepos = 0;
1433            val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1434            if (U_FAILURE(status)) {
1435                log_err("parseInt64 returned error: %s\n", myErrorName(status));
1436            } else if (val64 != U_INT64_MIN) {
1437                log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1438            }
1439
1440            status = U_ZERO_ERROR;
1441            parsepos = 0;
1442            valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1443            if (U_FAILURE(status)) {
1444                log_err("parseDouble returned error: %s\n", myErrorName(status));
1445            } else if (valDouble != doubleInt64Min) {
1446                log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1447            }
1448        }
1449
1450        unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status);
1451        if (U_FAILURE(status)) {
1452            log_err("error in unum_format(): %s\n", myErrorName(status));
1453        } else {
1454            log_verbose("format doubleBig: '%s'\n", result);
1455            parsepos = 0;
1456            val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1457            if (status != U_INVALID_FORMAT_ERROR) {
1458                log_err("parse didn't report error: %s\n", myErrorName(status));
1459            } else if (val32 != INT32_MAX) {
1460                log_err("parse didn't pin return value, got: %d\n", val32);
1461            }
1462
1463            status = U_ZERO_ERROR;
1464            parsepos = 0;
1465            val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1466            if (status != U_INVALID_FORMAT_ERROR) {
1467                log_err("parseInt64 didn't report error error: %s\n", myErrorName(status));
1468            } else if (val64 != U_INT64_MAX) {
1469                log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1470            }
1471
1472            status = U_ZERO_ERROR;
1473            parsepos = 0;
1474            valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1475            if (U_FAILURE(status)) {
1476                log_err("parseDouble returned error: %s\n", myErrorName(status));
1477            } else if (!withinErr(valDouble, doubleBig, 1e-15)) {
1478                log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1479            }
1480        }
1481
1482		u_uastrcpy(result, "5.06e-27");
1483        parsepos = 0;
1484        valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1485        if (U_FAILURE(status)) {
1486            log_err("parseDouble() returned error: %s\n", myErrorName(status));
1487        } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) {
1488            log_err("parseDouble() returned incorrect value, got: %g\n", valDouble);
1489        }
1490    }
1491    unum_close(fmt);
1492}
1493
1494
1495static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
1496    char temp[512];
1497    UChar buffer[512];
1498    int32_t BUFSIZE = sizeof(buffer)/sizeof(buffer[0]);
1499    double vals[] = {
1500        -.2, 0, .2, 5.5, 15.2, 250, 123456789
1501    };
1502    int i;
1503
1504    for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) {
1505        UErrorCode status = U_ZERO_ERROR;
1506        unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1507        if (U_FAILURE(status)) {
1508            log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1509        } else {
1510            u_austrcpy(temp, buffer);
1511            log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1512        }
1513    }
1514
1515    /* check APIs now */
1516    {
1517        UErrorCode status = U_ZERO_ERROR;
1518        UParseError perr;
1519        u_uastrcpy(buffer, "#,##0.0#");
1520        unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status);
1521        if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1522            log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status));
1523        }
1524    }
1525
1526    {
1527        int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1528        log_verbose("lenient: 0x%x\n", isLenient);
1529        if (isLenient != FALSE) {
1530            log_err("didn't expect lenient value: %d\n", isLenient);
1531        }
1532
1533        unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE);
1534        isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1535        if (isLenient != TRUE) {
1536            log_err("didn't expect lenient value after set: %d\n", isLenient);
1537        }
1538    }
1539
1540    {
1541        double val2;
1542        double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE);
1543        if (val != -1) {
1544            log_err("didn't expect double attribute\n");
1545        }
1546        val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1547        if ((val == -1) == isDecimal) {
1548            log_err("didn't expect -1 rounding increment\n");
1549        }
1550        unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5);
1551        val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1552        if (isDecimal && (val2 - val != .5)) {
1553            log_err("set rounding increment had no effect on decimal format");
1554        }
1555    }
1556
1557    {
1558        UErrorCode status = U_ZERO_ERROR;
1559        int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1560        if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1561            log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status));
1562        }
1563        if (U_SUCCESS(status)) {
1564            u_austrcpy(temp, buffer);
1565            log_verbose("default ruleset: '%s'\n", temp);
1566        }
1567
1568        status = U_ZERO_ERROR;
1569        len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status);
1570        if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1571            log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status));
1572        }
1573        if (U_SUCCESS(status)) {
1574            u_austrcpy(temp, buffer);
1575            log_verbose("public rulesets: '%s'\n", temp);
1576
1577            /* set the default ruleset to the first one found, and retry */
1578
1579            if (len > 0) {
1580                for (i = 0; i < len && temp[i] != ';'; ++i){};
1581                if (i < len) {
1582                    buffer[i] = 0;
1583                    unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status);
1584                    if (U_FAILURE(status)) {
1585                        log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status));
1586                    } else {
1587                        int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1588                        if (U_FAILURE(status)) {
1589                            log_err("could not fetch default ruleset: '%s'\n", u_errorName(status));
1590                        } else if (len2 != i) {
1591                            u_austrcpy(temp, buffer);
1592                            log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp);
1593                        } else {
1594                            for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) {
1595                                status = U_ZERO_ERROR;
1596                                unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1597                                if (U_FAILURE(status)) {
1598                                    log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1599                                } else {
1600                                    u_austrcpy(temp, buffer);
1601                                    log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1602                                }
1603                            }
1604                        }
1605                    }
1606                }
1607            }
1608        }
1609    }
1610
1611    {
1612        UErrorCode status = U_ZERO_ERROR;
1613        unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status);
1614        if (U_SUCCESS(status)) {
1615            u_austrcpy(temp, buffer);
1616            log_verbose("pattern: '%s'\n", temp);
1617        } else if (status != U_BUFFER_OVERFLOW_ERROR) {
1618            log_err("toPattern failed unexpectedly: %s\n", u_errorName(status));
1619        } else {
1620            log_verbose("pattern too long to display\n");
1621        }
1622    }
1623
1624    {
1625        UErrorCode status = U_ZERO_ERROR;
1626        int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status);
1627        if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1628            log_err("unexpected error getting symbol: '%s'\n", u_errorName(status));
1629        }
1630
1631        unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status);
1632        if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1633            log_err("unexpected error setting symbol: '%s'\n", u_errorName(status));
1634        }
1635    }
1636}
1637
1638static void TestNonExistentCurrency() {
1639    UNumberFormat *format;
1640    UErrorCode status = U_ZERO_ERROR;
1641    UChar currencySymbol[8];
1642    static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
1643
1644    /* Get a non-existent currency and make sure it returns the correct currency code. */
1645    format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status);
1646    if (format == NULL || U_FAILURE(status)) {
1647        log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status));
1648    }
1649    else {
1650        unum_getSymbol(format,
1651                UNUM_CURRENCY_SYMBOL,
1652                currencySymbol,
1653                sizeof(currencySymbol)/sizeof(currencySymbol[0]),
1654                &status);
1655        if (u_strcmp(currencySymbol, QQQ) != 0) {
1656            log_err("unum_open set the currency to QQQ\n");
1657        }
1658    }
1659    unum_close(format);
1660}
1661
1662static void TestRBNFFormat() {
1663    UErrorCode status;
1664    UParseError perr;
1665    UChar pat[1024];
1666    UChar tempUChars[512];
1667    UNumberFormat *formats[5];
1668    int COUNT = sizeof(formats)/sizeof(formats[0]);
1669    int i;
1670
1671    for (i = 0; i < COUNT; ++i) {
1672        formats[i] = 0;
1673    }
1674
1675    /* instantiation */
1676    status = U_ZERO_ERROR;
1677    u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)");
1678    formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status);
1679    if (U_FAILURE(status)) {
1680        log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
1681        return;
1682    }
1683
1684    status = U_ZERO_ERROR;
1685    formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status);
1686    if (U_FAILURE(status)) {
1687        log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1688        return;
1689    }
1690
1691    status = U_ZERO_ERROR;
1692    formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status);
1693    if (U_FAILURE(status)) {
1694        log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
1695        return;
1696    }
1697
1698    status = U_ZERO_ERROR;
1699    formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status);
1700    if (U_FAILURE(status)) {
1701        log_err_status(status, "unable to open duration %s\n", u_errorName(status));
1702        return;
1703    }
1704
1705    status = U_ZERO_ERROR;
1706    u_uastrcpy(pat,
1707        "%standard:\n"
1708        "-x: minus >>;\n"
1709        "x.x: << point >>;\n"
1710        "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1711        "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1712        "seventeen; eighteen; nineteen;\n"
1713        "20: twenty[->>];\n"
1714        "30: thirty[->>];\n"
1715        "40: forty[->>];\n"
1716        "50: fifty[->>];\n"
1717        "60: sixty[->>];\n"
1718        "70: seventy[->>];\n"
1719        "80: eighty[->>];\n"
1720        "90: ninety[->>];\n"
1721        "100: =#,##0=;\n");
1722    u_uastrcpy(tempUChars,
1723        "%simple:\n"
1724        "=%standard=;\n"
1725        "20: twenty[ and change];\n"
1726        "30: thirty[ and change];\n"
1727        "40: forty[ and change];\n"
1728        "50: fifty[ and change];\n"
1729        "60: sixty[ and change];\n"
1730        "70: seventy[ and change];\n"
1731        "80: eighty[ and change];\n"
1732        "90: ninety[ and change];\n"
1733        "100: =#,##0=;\n"
1734        "%bogus:\n"
1735        "0.x: tiny;\n"
1736        "x.x: << point something;\n"
1737        "=%standard=;\n"
1738        "20: some reasonable number;\n"
1739        "100: some substantial number;\n"
1740        "100,000,000: some huge number;\n");
1741    /* This is to get around some compiler warnings about char * string length. */
1742    u_strcat(pat, tempUChars);
1743    formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status);
1744    if (U_FAILURE(status)) {
1745        log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
1746    }
1747    if (U_FAILURE(status)) {
1748        log_err_status(status, "Something failed with %s\n", u_errorName(status));
1749        return;
1750    }
1751
1752    for (i = 0; i < COUNT; ++i) {
1753        log_verbose("\n\ntesting format %d\n", i);
1754        test_fmt(formats[i], (UBool)(i == 0));
1755    }
1756
1757    #define FORMAT_BUF_CAPACITY 64
1758    {
1759        UChar fmtbuf[FORMAT_BUF_CAPACITY];
1760        int32_t len;
1761        double nanvalue = uprv_getNaN();
1762        status = U_ZERO_ERROR;
1763        len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1764        if (U_FAILURE(status)) {
1765            log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status));
1766        } else {
1767            UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1768            if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) {
1769                log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1770            }
1771        }
1772    }
1773
1774    for (i = 0; i < COUNT; ++i) {
1775        unum_close(formats[i]);
1776    }
1777}
1778
1779static void TestCurrencyRegression(void) {
1780/*
1781 I've found a case where unum_parseDoubleCurrency is not doing what I
1782expect.  The value I pass in is $1234567890q123460000.00 and this
1783returns with a status of zero error & a parse pos of 22 (I would
1784expect a parse error at position 11).
1785
1786I stepped into DecimalFormat::subparse() and it looks like it parses
1787the first 10 digits and then stops parsing at the q but doesn't set an
1788error. Then later in DecimalFormat::parse() the value gets crammed
1789into a long (which greatly truncates the value).
1790
1791This is very problematic for me 'cause I try to remove chars that are
1792invalid but this allows my users to enter bad chars and truncates
1793their data!
1794*/
1795
1796    UChar buf[1024];
1797    UChar currency[8];
1798    char acurrency[16];
1799    double d;
1800    UNumberFormat *cur;
1801    int32_t pos;
1802    UErrorCode status  = U_ZERO_ERROR;
1803    const int32_t expected = 11;
1804
1805    currency[0]=0;
1806    u_uastrcpy(buf, "$1234567890q643210000.00");
1807    cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status);
1808
1809    if(U_FAILURE(status)) {
1810        log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
1811        return;
1812    }
1813
1814    status = U_ZERO_ERROR; /* so we can test it later. */
1815    pos = 0;
1816
1817    d = unum_parseDoubleCurrency(cur,
1818                         buf,
1819                         -1,
1820                         &pos, /* 0 = start */
1821                         currency,
1822                         &status);
1823
1824    u_austrcpy(acurrency, currency);
1825
1826    if(U_FAILURE(status) || (pos != expected)) {
1827        log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1828            expected, d, u_errorName(status), pos, acurrency);
1829    } else {
1830        log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency);
1831    }
1832
1833    unum_close(cur);
1834}
1835
1836static void TestTextAttributeCrash(void) {
1837    UChar ubuffer[64] = {0x0049,0x004E,0x0052,0};
1838    static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1839    static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1840    int32_t used;
1841    UErrorCode status = U_ZERO_ERROR;
1842    UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
1843    if (U_FAILURE(status)) {
1844        log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
1845        return;
1846    }
1847    unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status);
1848    /*
1849     * the usual negative prefix and suffix seem to be '($' and ')' at this point
1850     * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1851     */
1852    used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status);
1853    unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status);
1854    if (U_FAILURE(status)) {
1855        log_err("FAILED 2\n"); exit(1);
1856    }
1857    log_verbose("attempting to format...\n");
1858    used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
1859    if (U_FAILURE(status) || 64 < used) {
1860        log_err("Failed formatting %s\n", u_errorName(status));
1861        return;
1862    }
1863    if (u_strcmp(expectedNeg, ubuffer) == 0) {
1864        log_err("Didn't get expected negative result\n");
1865    }
1866    used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
1867    if (U_FAILURE(status) || 64 < used) {
1868        log_err("Failed formatting %s\n", u_errorName(status));
1869        return;
1870    }
1871    if (u_strcmp(expectedPos, ubuffer) == 0) {
1872        log_err("Didn't get expected positive result\n");
1873    }
1874    unum_close(nf);
1875}
1876
1877static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
1878    UErrorCode status = U_ZERO_ERROR;
1879    UChar myString[20];
1880    char tmpbuf[200];
1881    double aNumber = -1.0;
1882    unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
1883    log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
1884    if(U_FAILURE(status)) {
1885      log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
1886        return;
1887    }
1888    aNumber = unum_parse(nf, myString, -1, NULL, &status);
1889    if(U_FAILURE(status)) {
1890      log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
1891        return;
1892    }
1893    if(uprv_fabs(aNumber-myNumber)>.001) {
1894      log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
1895    } else {
1896      log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
1897    }
1898}
1899
1900static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
1901  TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
1902  TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
1903}
1904
1905static void TestNBSPInPattern(void) {
1906    UErrorCode status = U_ZERO_ERROR;
1907    UNumberFormat* nf = NULL;
1908    const char *testcase;
1909
1910
1911    testcase="ar_AE UNUM_CURRENCY";
1912    nf  = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
1913    if(U_FAILURE(status) || nf == NULL) {
1914      log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
1915        return;
1916    }
1917    TestNBSPPatternRT(testcase, nf);
1918
1919    /* if we don't have CLDR 1.6 data, bring out the problem anyways */
1920    {
1921#define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
1922        UChar pat[200];
1923        testcase = "ar_AE special pattern: " SPECIAL_PATTERN;
1924        u_unescape(SPECIAL_PATTERN, pat, sizeof(pat)/sizeof(pat[0]));
1925        unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
1926        if(U_FAILURE(status)) {
1927            log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status));
1928        } else {
1929            TestNBSPPatternRT(testcase, nf);
1930        }
1931#undef SPECIAL_PATTERN
1932    }
1933    unum_close(nf); status = U_ZERO_ERROR;
1934
1935    testcase="ar_AE UNUM_DECIMAL";
1936    nf  = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status);
1937    if(U_FAILURE(status)) {
1938        log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
1939    }
1940    TestNBSPPatternRT(testcase, nf);
1941    unum_close(nf); status = U_ZERO_ERROR;
1942
1943    testcase="ar_AE UNUM_PERCENT";
1944    nf  = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status);
1945    if(U_FAILURE(status)) {
1946        log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
1947    }
1948    TestNBSPPatternRT(testcase, nf);
1949    unum_close(nf); status = U_ZERO_ERROR;
1950
1951
1952
1953}
1954static void TestCloneWithRBNF(void) {
1955    UChar pattern[1024];
1956    UChar pat2[512];
1957    UErrorCode status = U_ZERO_ERROR;
1958    UChar buffer[256];
1959    UChar buffer_cloned[256];
1960    char temp1[256];
1961    char temp2[256];
1962    UNumberFormat *pform_cloned;
1963    UNumberFormat *pform;
1964
1965    u_uastrcpy(pattern,
1966        "%main:\n"
1967        "0.x: >%%millis-only>;\n"
1968        "x.0: <%%duration<;\n"
1969        "x.x: <%%durationwithmillis<>%%millis-added>;\n"
1970        "-x: ->>;%%millis-only:\n"
1971        "1000: 00:00.<%%millis<;\n"
1972        "%%millis-added:\n"
1973        "1000: .<%%millis<;\n"
1974        "%%millis:\n"
1975        "0: =000=;\n"
1976        "%%duration:\n"
1977        "0: =%%seconds-only=;\n"
1978        "60: =%%min-sec=;\n"
1979        "3600: =%%hr-min-sec=;\n"
1980        "86400/86400: <%%ddaayyss<[, >>];\n"
1981        "%%durationwithmillis:\n"
1982        "0: =%%seconds-only=;\n"
1983        "60: =%%min-sec=;\n"
1984        "3600: =%%hr-min-sec=;\n"
1985        "86400/86400: <%%ddaayyss<, >>;\n");
1986    u_uastrcpy(pat2,
1987        "%%seconds-only:\n"
1988        "0: 0:00:=00=;\n"
1989        "%%min-sec:\n"
1990        "0: :=00=;\n"
1991        "0/60: 0:<00<>>;\n"
1992        "%%hr-min-sec:\n"
1993        "0: :=00=;\n"
1994        "60/60: <00<>>;\n"
1995        "3600/60: <0<:>>>;\n"
1996        "%%ddaayyss:\n"
1997        "0 days;\n"
1998        "1 day;\n"
1999        "=0= days;");
2000
2001    /* This is to get around some compiler warnings about char * string length. */
2002    u_strcat(pattern, pat2);
2003
2004    pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status);
2005    unum_formatDouble(pform, 3600, buffer, 256, NULL, &status);
2006
2007    pform_cloned = unum_clone(pform,&status);
2008    unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status);
2009
2010    unum_close(pform);
2011    unum_close(pform_cloned);
2012
2013    if (u_strcmp(buffer,buffer_cloned)) {
2014        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));
2015    }
2016}
2017
2018
2019static void TestNoExponent(void) {
2020    UErrorCode status = U_ZERO_ERROR;
2021    UChar str[100];
2022    const char *cstr;
2023    UNumberFormat *fmt;
2024    int32_t pos;
2025    int32_t expect = 0;
2026    int32_t num;
2027
2028    fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status);
2029
2030    if(U_FAILURE(status) || fmt == NULL) {
2031        log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status));
2032        return;
2033    }
2034
2035    cstr = "10E6";
2036    u_uastrcpy(str, cstr);
2037    expect = 10000000;
2038    pos = 0;
2039    num = unum_parse(fmt, str, -1, &pos, &status);
2040    ASSERT_TRUE(pos==4);
2041    if(U_FAILURE(status)) {
2042        log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2043    } else if(expect!=num) {
2044        log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2045    } else {
2046        log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2047    }
2048
2049    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2050
2051    unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2052    log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2053
2054    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2055
2056    pos = 0;
2057    expect=10;
2058    num = unum_parse(fmt, str, -1, &pos, &status);
2059    if(num==10000000) {
2060        log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr);
2061    } else if(num==expect) {
2062        log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr);
2063    }
2064    ASSERT_TRUE(pos==2);
2065
2066    status = U_ZERO_ERROR;
2067
2068    unum_close(fmt);
2069
2070    /* ok, now try scientific */
2071    fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status);
2072    assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status);
2073
2074    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2075
2076    cstr = "10E6";
2077    u_uastrcpy(str, cstr);
2078    expect = 10000000;
2079    pos = 0;
2080    num = unum_parse(fmt, str, -1, &pos, &status);
2081    ASSERT_TRUE(pos==4);
2082    if(U_FAILURE(status)) {
2083        log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2084    } else if(expect!=num) {
2085        log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2086    } else {
2087        log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2088    }
2089
2090    unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2091    log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2092
2093    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
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    unum_close(fmt);
2111}
2112
2113static void TestMaxInt(void) {
2114    UErrorCode status = U_ZERO_ERROR;
2115    UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */
2116    UChar result1[1024] = { 0 }, result2[1024] = { 0 };
2117    int32_t len1, len2;
2118    UChar expect[] = { 0x0039, 0x0037, 0 };
2119    UNumberFormat *fmt = unum_open(
2120                  UNUM_PATTERN_DECIMAL,      /* style         */
2121                  &pattern_hash[0],          /* pattern       */
2122                  u_strlen(pattern_hash),    /* patternLength */
2123                  0,
2124                  0,                         /* parseErr      */
2125                  &status);
2126    if(U_FAILURE(status) || fmt == NULL) {
2127        log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status));
2128        return;
2129    }
2130
2131    unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2);
2132
2133    status = U_ZERO_ERROR;
2134    /* #1 */
2135    len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2136    result1[len1]=0;
2137    if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2138        log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2139    }
2140
2141    status = U_ZERO_ERROR;
2142    /* #2 */
2143    len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status);
2144    result2[len2]=0;
2145    if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2146        log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2147    }
2148
2149
2150
2151    /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2152    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0);
2153
2154    unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1);
2155    /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2156    ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1);
2157
2158    status = U_ZERO_ERROR;
2159    /* max int digits still '2' */
2160    len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2161    ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR);
2162    status = U_ZERO_ERROR;
2163
2164    /* But, formatting 97->'97' works fine. */
2165
2166    /* #1 */
2167    len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status);
2168    result1[len1]=0;
2169    if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2170        log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2171    }
2172
2173    status = U_ZERO_ERROR;
2174    /* #2 */
2175    len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status);
2176    result2[len2]=0;
2177    if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2178        log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2179    }
2180
2181
2182    unum_close(fmt);
2183}
2184
2185static void TestUFormattable(void) {
2186  UChar out2k[2048];
2187  // simple test for API docs
2188  {
2189    UErrorCode status = U_ZERO_ERROR;
2190    UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2191    if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2192      //! [unum_parseToUFormattable]
2193      const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2194      int32_t result = 0;
2195      UFormattable *ufmt = ufmt_open(&status);
2196      unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status);
2197      if (ufmt_isNumeric(ufmt)) {
2198          result = ufmt_getLong(ufmt, &status); /* == 123 */
2199      } /* else { ... } */
2200      ufmt_close(ufmt);
2201      //! [unum_parseToUFormattable]
2202      assertTrue("result == 123", (result == 123));
2203    }
2204    unum_close(unum);
2205  }
2206  // test with explicitly created ufmt_open
2207  {
2208    UChar buffer[2048];
2209    UErrorCode status = U_ZERO_ERROR;
2210    UFormattable *ufmt;
2211    UNumberFormat *unum;
2212    const char *pattern = "";
2213
2214    ufmt = ufmt_open(&status);
2215    unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2216    if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) {
2217
2218      pattern = "31337";
2219      log_verbose("-- pattern: %s\n", pattern);
2220      u_uastrcpy(buffer, pattern);
2221      unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2222      if(assertSuccess("unum_parseToUFormattable(31337)", &status)) {
2223        assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337);
2224        assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG);
2225        log_verbose("long = %d\n", ufmt_getLong(ufmt, &status));
2226        assertSuccess("ufmt_getLong()", &status);
2227      }
2228      unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2229      if(assertSuccess("unum_formatUFormattable(31337)", &status)) {
2230        assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2231      }
2232
2233      pattern = "3.14159";
2234      log_verbose("-- pattern: %s\n", pattern);
2235      u_uastrcpy(buffer, pattern);
2236      unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2237      if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) {
2238        assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15));
2239        assertSuccess("ufmt_getDouble()", &status);
2240        assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE);
2241        log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status));
2242      }
2243      unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2244      if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2245        assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2246      }
2247    }
2248    ufmt_close(ufmt);
2249    unum_close(unum);
2250  }
2251
2252  // test with auto-generated ufmt
2253  {
2254    UChar buffer[2048];
2255    UErrorCode status = U_ZERO_ERROR;
2256    UFormattable *ufmt = NULL;
2257    UNumberFormat *unum;
2258    const char *pattern = "73476730924573500000000"; // weight of the moon, kg
2259
2260    log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern);
2261    u_uastrcpy(buffer, pattern);
2262
2263    unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2264    if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2265
2266      ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */
2267                                   buffer, -1, NULL, &status);
2268      if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) {
2269        log_verbose("new formattable allocated at %p\n", (void*)ufmt);
2270        assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt));
2271        unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2272        if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2273          assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2274        }
2275
2276        log_verbose("double: %g\n",  ufmt_getDouble(ufmt, &status));
2277        assertSuccess("ufmt_getDouble()", &status);
2278
2279        log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status));
2280        assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status));
2281        // status is now a failure due to ufmt_getLong() above.
2282        // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2283      }
2284    }
2285
2286    unum_close(unum);
2287    ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable()
2288  }
2289}
2290
2291typedef struct {
2292    const char*  locale;
2293    const char*  numsys;
2294    int32_t      radix;
2295    UBool        isAlgorithmic;
2296    const UChar* description;
2297} NumSysTestItem;
2298
2299
2300static const UChar latnDesc[]    = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2301static const UChar romanDesc[]   = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2302static const UChar arabDesc[]    = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2303static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2304static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2305static const UChar hantDesc[]    = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2306                                    0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2307                                    0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2308
2309static const NumSysTestItem numSysTestItems[] = {
2310    //locale                         numsys    radix isAlgo  description
2311    { "en",                          "latn",    10,  FALSE,  latnDesc },
2312    { "en@numbers=roman",            "roman",   10,  TRUE,   romanDesc },
2313    { "en@numbers=finance",          "latn",    10,  FALSE,  latnDesc },
2314    { "ar",                          "arab",    10,  FALSE,  arabDesc },
2315    { "fa",                          "arabext", 10,  FALSE,  arabextDesc },
2316    { "zh_Hans@numbers=hanidec",     "hanidec", 10,  FALSE,  hanidecDesc },
2317    { "zh_Hant@numbers=traditional", "hant",    10,  TRUE,   hantDesc },
2318    { NULL,                          NULL,       0,  FALSE,  NULL },
2319};
2320enum { kNumSysDescripBufMax = 64 };
2321
2322static void TestUNumberingSystem(void) {
2323    const NumSysTestItem * itemPtr;
2324    UNumberingSystem * unumsys;
2325    UEnumeration * uenum;
2326    const char * numsys;
2327    UErrorCode status;
2328
2329    for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) {
2330        status = U_ZERO_ERROR;
2331        unumsys = unumsys_open(itemPtr->locale, &status);
2332        if ( U_SUCCESS(status) ) {
2333            UChar ubuf[kNumSysDescripBufMax];
2334            int32_t ulen, radix = unumsys_getRadix(unumsys);
2335            UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys);
2336            numsys = unumsys_getName(unumsys);
2337            if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) {
2338                log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2339                        itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic);
2340            }
2341            ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status);
2342            if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) {
2343                log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status));
2344            }
2345            unumsys_close(unumsys);
2346        } else {
2347            log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status));
2348        }
2349    }
2350
2351    status = U_ZERO_ERROR;
2352    uenum = unumsys_openAvailableNames(&status);
2353    if ( U_SUCCESS(status) ) {
2354        int32_t numsysCount = 0;
2355        // sanity check for a couple of number systems that must be in the enumeration
2356        UBool foundLatn = FALSE;
2357        UBool foundArab = FALSE;
2358        while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
2359            status = U_ZERO_ERROR;
2360            unumsys = unumsys_openByName(numsys, &status);
2361            if ( U_SUCCESS(status) ) {
2362                numsysCount++;
2363                if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
2364                if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
2365                unumsys_close(unumsys);
2366            } else {
2367                log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2368                        numsys, myErrorName(status));
2369            }
2370        }
2371        uenum_close(uenum);
2372        if ( numsysCount < 40 || !foundLatn || !foundArab ) {
2373            log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2374                    numsysCount, foundLatn, foundArab);
2375        }
2376    } else {
2377        log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
2378    }
2379}
2380
2381#endif /* #if !UCONFIG_NO_FORMATTING */
2382