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