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