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