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