1 /********************************************************************
3 * Copyright (c) 1997-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6 /********************************************************************************
10 * Madhu Katragadda Creation
12 * Modification History:
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 *********************************************************************************
20 /* C API TEST FOR NUMBER FORMAT */
22 #include "unicode/utypes.h"
24 #if !UCONFIG_NO_FORMATTING
26 #include "unicode/uloc.h"
27 #include "unicode/umisc.h"
28 #include "unicode/unum.h"
29 #include "unicode/ustring.h"
36 #define LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
38 void addNumForTest(TestNode
** root
);
39 static void TestTextAttributeCrash(void);
40 static void TestNBSPInPattern(void);
41 static void TestInt64Parse(void);
42 static void TestParseCurrency(void);
43 static void TestParseAltNum(void);
45 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
47 void addNumForTest(TestNode
** root
)
49 TESTCASE(TestNumberFormat
);
50 TESTCASE(TestSpelloutNumberParse
);
51 TESTCASE(TestSignificantDigits
);
52 TESTCASE(TestSigDigRounding
);
53 TESTCASE(TestNumberFormatPadding
);
54 TESTCASE(TestInt64Format
);
55 TESTCASE(TestNonExistentCurrency
);
56 TESTCASE(TestCurrencyRegression
);
57 TESTCASE(TestTextAttributeCrash
);
58 TESTCASE(TestRBNFFormat
);
59 TESTCASE(TestNBSPInPattern
);
60 TESTCASE(TestInt64Parse
);
61 TESTCASE(TestParseZero
);
62 TESTCASE(TestParseCurrency
);
63 TESTCASE(TestParseAltNum
);
64 TESTCASE(TestCloneWithRBNF
);
67 /** copy src to dst with unicode-escapes for values < 0x20 and > 0x7e, null terminate if possible */
68 static int32_t ustrToAstr(const UChar
* src
, int32_t srcLength
, char* dst
, int32_t dstLength
) {
69 static const char hex
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
72 const char *e
= p
+ dstLength
;
78 srcLength
= (int32_t)(s
- src
);
80 while (p
< e
&& --srcLength
>= 0) {
82 if (c
== 0xd || c
== 0xa || c
== 0x9 || (c
>= 0x20 && c
<= 0x7e)) {
83 *p
++ = (char) c
& 0x7f;
84 } else if (e
- p
>= 6) {
87 *p
++ = hex
[(c
>> 12) & 0xf];
88 *p
++ = hex
[(c
>> 8) & 0xf];
89 *p
++ = hex
[(c
>> 4) & 0xf];
98 return (int32_t)(p
- dst
);
101 /* test Parse int 64 */
103 static void TestInt64Parse()
106 UErrorCode st
= U_ZERO_ERROR
;
107 UErrorCode
* status
= &st
;
109 const char* st1
= "009223372036854775808";
118 u_charsToUChars(st1
, text
, size
);
119 nf
= unum_open(UNUM_DEFAULT
, NULL
, -1, NULL
, NULL
, status
);
121 if(U_FAILURE(*status
))
123 log_data_err("Error in unum_open() %s \n", myErrorName(*status
));
127 log_verbose("About to test unum_parseInt64() with out of range number\n");
129 a
= unum_parseInt64(nf
, text
, size
, 0, status
);
132 if(!U_FAILURE(*status
))
134 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status
));
138 log_verbose("unum_parseInt64() successful\n");
145 /* test Number Format API */
146 static void TestNumberFormat()
157 int32_t resultlength
;
158 int32_t resultlengthneeded
;
162 double d
= -10456.37;
163 double a
= 1234.56, a1
= 1235.0;
164 int32_t l
= 100000000;
170 UNumberFormatAttribute attr
;
171 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
173 UErrorCode status
=U_ZERO_ERROR
;
174 UNumberFormatStyle style
= UNUM_DEFAULT
;
175 UNumberFormat
*pattern
;
176 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
177 *cur_frpattern
, *myclone
, *spellout_def
;
179 /* Testing unum_open() with various Numberformat styles and locales*/
180 status
= U_ZERO_ERROR
;
181 log_verbose("Testing unum_open() with default style and locale\n");
182 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
184 /* Might as well pack it in now if we can't even get a default NumberFormat... */
185 if(U_FAILURE(status
))
187 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status
));
191 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
192 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
193 if(U_FAILURE(status
))
194 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
196 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
198 /* Can't hardcode the result to assume the default locale is "en_US". */
199 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
200 if(U_FAILURE(status
))
201 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
202 myErrorName(status
) );
204 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
205 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
206 if(U_FAILURE(status
))
207 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
208 myErrorName(status
));
210 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
212 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
213 if(U_FAILURE(status
))
214 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
216 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
217 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
218 if(U_FAILURE(status
))
219 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
221 log_verbose("\nTesting unum_open(spellout, NULL, status)");
223 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
224 if(U_FAILURE(status
))
225 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
227 /* Testing unum_clone(..) */
228 log_verbose("\nTesting unum_clone(fmt, status)");
229 status
= U_ZERO_ERROR
;
230 myclone
= unum_clone(def
,&status
);
231 if(U_FAILURE(status
))
232 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
235 log_verbose("unum_clone() successful\n");
238 /*Testing unum_getAvailable() and unum_countAvailable()*/
239 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
240 numlocales
=unum_countAvailable();
242 log_err("error in countAvailable");
244 log_verbose("unum_countAvialable() successful\n");
245 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
247 for(i
=0;i
<numlocales
;i
++)
249 log_verbose("%s\n", unum_getAvailable(i
));
250 if (unum_getAvailable(i
) == 0)
251 log_err("No locale for which number formatting patterns are applicable\n");
253 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
257 /*Testing unum_format() and unum_formatdouble()*/
258 u_uastrcpy(temp1
, "$100,000,000.00");
260 log_verbose("\nTesting unum_format() \n");
262 pos1
.field
= UNUM_INTEGER_FIELD
;
263 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
264 if(status
==U_BUFFER_OVERFLOW_ERROR
)
267 resultlength
=resultlengthneeded
+1;
268 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
269 /* for (i = 0; i < 100000; i++) */
271 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
275 if(U_FAILURE(status
))
277 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
279 if(u_strcmp(result
, temp1
)==0)
280 log_verbose("Pass: Number formatting using unum_format() successful\n");
282 log_err("Fail: Error in number Formatting using unum_format()\n");
283 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
284 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
286 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
287 pos1
.beginIndex
, pos1
.endIndex
);
292 log_verbose("\nTesting unum_formatDouble()\n");
293 u_uastrcpy(temp1
, "($10,456.37)");
295 pos2
.field
= UNUM_FRACTION_FIELD
;
296 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
297 if(status
==U_BUFFER_OVERFLOW_ERROR
)
300 resultlength
=resultlengthneeded
+1;
301 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
302 /* for (i = 0; i < 100000; i++) */
304 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
307 if(U_FAILURE(status
))
309 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
311 if(result
&& u_strcmp(result
, temp1
)==0)
312 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
314 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
315 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
316 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
318 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
319 pos1
.beginIndex
, pos1
.endIndex
);
322 /* Testing unum_parse() and unum_parseDouble() */
323 log_verbose("\nTesting unum_parseDouble()\n");
324 /* for (i = 0; i < 100000; i++)*/
328 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
331 log_err("result is NULL\n");
333 if(U_FAILURE(status
))
335 log_err("parse failed. The error is : %s\n", myErrorName(status
));
339 log_err("Fail: Error in parsing\n");
341 log_verbose("Pass: parsing successful\n");
347 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
348 log_verbose("\nTesting unum_formatDoubleCurrency\n");
349 u_uastrcpy(temp1
, "Y1,235");
350 temp1
[0] = 0xA5; /* Yen sign */
351 u_uastrcpy(temp
, "JPY");
353 pos2
.field
= UNUM_INTEGER_FIELD
;
354 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
355 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
357 resultlength
=resultlengthneeded
+1;
358 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
359 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
361 if (U_FAILURE(status
)) {
362 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
364 if (result
&& u_strcmp(result
, temp1
)==0) {
365 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
367 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
369 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
370 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
372 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
373 pos1
.beginIndex
, pos1
.endIndex
);
376 log_verbose("\nTesting unum_parseDoubleCurrency\n");
378 if (result
== NULL
) {
379 log_err("result is NULL\n");
382 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
383 if (U_FAILURE(status
)) {
384 log_err("parse failed. The error is : %s\n", myErrorName(status
));
386 /* Note: a==1234.56, but on parse expect a1=1235.0 */
388 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
390 log_verbose("Pass: parsed currency ammount successfully\n");
392 if (u_strcmp(temp2
, temp
)==0) {
393 log_verbose("Pass: parsed correct currency\n");
395 log_err("Fail: parsed incorrect currency\n");
403 /* performance testing */
404 u_uastrcpy(temp1
, "$462.12345");
405 resultlength
=u_strlen(temp1
);
406 /* for (i = 0; i < 100000; i++) */
409 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
411 if(U_FAILURE(status
))
413 log_err("parse failed. The error is : %s\n", myErrorName(status
));
417 * Note: "for strict standard conformance all operations and constants are now supposed to be
418 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
423 log_err("Fail: Error in parsing\n");
425 log_verbose("Pass: parsing successful\n");
429 u_uastrcpy(temp1
, "($10,456.3E1])");
431 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
432 if(U_SUCCESS(status
))
434 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
438 log_verbose("\nTesting unum_format()\n");
442 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
443 if(status
==U_BUFFER_OVERFLOW_ERROR
)
446 resultlength
=resultlengthneeded
+1;
447 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
448 /* for (i = 0; i < 100000; i++)*/
450 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
453 if(U_FAILURE(status
))
455 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
459 log_verbose("\nTesting unum_parse()\n");
460 /* for (i = 0; i < 100000; i++) */
463 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
465 if(U_FAILURE(status
))
467 log_err("parse failed. The error is : %s\n", myErrorName(status
));
471 log_err("Fail: Error in parsing\n");
473 log_verbose("Pass: parsing successful\n");
477 /* create a number format using unum_openPattern(....)*/
478 log_verbose("\nTesting unum_openPattern()\n");
479 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
480 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
481 if(U_FAILURE(status
))
483 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
486 log_verbose("Pass: unum_openPattern() works fine\n");
488 /*test for unum_toPattern()*/
489 log_verbose("\nTesting unum_toPattern()\n");
491 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
492 if(status
==U_BUFFER_OVERFLOW_ERROR
)
495 resultlength
=resultlengthneeded
+1;
496 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
497 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
499 if(U_FAILURE(status
))
501 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
505 if(u_strcmp(result
, temp1
)!=0)
506 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
508 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
512 /*Testing unum_getSymbols() and unum_setSymbols()*/
513 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
514 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
516 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
517 if(status
==U_BUFFER_OVERFLOW_ERROR
)
520 resultlength
=resultlengthneeded
+1;
521 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
522 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
524 if(U_FAILURE(status
))
526 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
530 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
531 if(U_FAILURE(status
))
533 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
538 /*getting the symbols of cur_def */
539 /*set the symbols of cur_frpattern to cur_def */
540 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
542 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
543 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
544 if(U_FAILURE(status
))
546 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
550 /*format to check the result */
552 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
553 if(status
==U_BUFFER_OVERFLOW_ERROR
)
556 resultlength
=resultlengthneeded
+1;
557 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
558 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
560 if(U_FAILURE(status
))
562 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
565 if(U_FAILURE(status
)){
566 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
568 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
570 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
572 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
573 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
574 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
576 log_err("Fail: error in getting symbols\n");
579 log_verbose("Pass: get and set symbols successful\n");
582 /*format and check with the previous result */
585 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
586 if(status
==U_BUFFER_OVERFLOW_ERROR
)
589 resultlength
=resultlengthneeded
+1;
590 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
592 if(U_FAILURE(status
))
594 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
597 * This test fails because we have not called unum_applyPattern().
598 * Currently, such an applyPattern() does not exist on the C API, and
599 * we have jitterbug 411 for it.
600 * Since it is close to the 1.5 release, I (markus) am disabling this test just
601 * for this release (I added the test itself only last week).
602 * For the next release, we need to fix this.
603 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
605 if(u_strcmp(result
, temp1
) != 0) {
606 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
614 /* Testing unum_get/setSymbol() */
615 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
616 symbol
[0] = (UChar
)(0x41 + i
);
617 symbol
[1] = (UChar
)(0x61 + i
);
618 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
619 if(U_FAILURE(status
)) {
620 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
624 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
625 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
626 if(U_FAILURE(status
)) {
627 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
630 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
631 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
634 /*try getting from a bogus symbol*/
635 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
636 if(U_SUCCESS(status
)){
637 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
639 if(U_FAILURE(status
)){
640 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
641 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
646 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
647 log_verbose("\nTesting getting and setting text attributes\n");
649 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
650 if(U_FAILURE(status
))
652 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
654 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
655 if(U_FAILURE(status
))
657 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
659 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
660 if(U_FAILURE(status
))
662 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
664 if(u_strcmp(suffix
,temp
)!=0)
665 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
667 log_verbose("Pass: setting and getting suffix works fine\n");
668 /*set it back to normal */
669 u_uastrcpy(temp
,"$");
670 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
672 /*checking some more text setter conditions */
673 u_uastrcpy(prefix
, "+");
674 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
675 if(U_FAILURE(status
))
677 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
679 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
680 if(U_FAILURE(status
))
682 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
685 if(u_strcmp(prefix
, temp
)!=0)
686 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
688 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
690 u_uastrcpy(prefix
, "+");
691 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
692 if(U_FAILURE(status
))
694 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
696 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
697 if(U_FAILURE(status
))
699 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
701 if(u_strcmp(prefix
, temp
)!=0)
702 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
704 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
706 u_uastrcpy(suffix
, "+");
707 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
708 if(U_FAILURE(status
))
710 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
713 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
714 if(U_FAILURE(status
))
716 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
718 if(u_strcmp(suffix
, temp
)!=0)
719 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
721 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
723 u_uastrcpy(suffix
, "++");
724 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
725 if(U_FAILURE(status
))
727 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
730 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
731 if(U_FAILURE(status
))
733 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
735 if(u_strcmp(suffix
, temp
)!=0)
736 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
738 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
740 /*Testing unum_getAttribute and unum_setAttribute() */
741 log_verbose("\nTesting get and set Attributes\n");
742 attr
=UNUM_GROUPING_SIZE
;
743 newvalue
=unum_getAttribute(def
, attr
);
745 unum_setAttribute(def
, attr
, newvalue
);
746 if(unum_getAttribute(def
,attr
)!=2)
747 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
749 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
751 attr
=UNUM_MULTIPLIER
;
752 newvalue
=unum_getAttribute(def
, attr
);
754 unum_setAttribute(def
, attr
, newvalue
);
755 if(unum_getAttribute(def
,attr
) != 8)
756 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
758 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
760 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
761 newvalue
=unum_getAttribute(def
, attr
);
763 unum_setAttribute(def
, attr
, newvalue
);
764 if(unum_getAttribute(def
,attr
) != 2)
765 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
767 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
769 /*testing set and get Attributes extensively */
770 log_verbose("\nTesting get and set attributes extensively\n");
771 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
773 newvalue
=unum_getAttribute(fr
, attr
);
774 unum_setAttribute(def
, attr
, newvalue
);
775 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
776 log_err("error in setting and getting attributes\n");
778 log_verbose("Pass: attributes set and retrieved successfully\n");
781 /*testing spellout format to make sure we can use it successfully.*/
782 log_verbose("\nTesting spellout format\n");
785 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
786 for (i
= 0; i
< LENGTH(values
); ++i
) {
789 int32_t value
= values
[i
];
790 status
= U_ZERO_ERROR
;
791 len
= unum_format(spellout_def
, value
, buffer
, LENGTH(buffer
), NULL
, &status
);
792 if(U_FAILURE(status
)) {
793 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
798 ustrToAstr(buffer
, len
, logbuf
, LENGTH(logbuf
));
799 log_verbose("formatted %d as '%s', length: %d\n", value
, logbuf
, len
);
801 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
802 if (U_FAILURE(status
)) {
803 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
804 } else if (parseResult
!= value
) {
805 log_err("unum_format result %d != value %d\n", parseResult
, value
);
811 log_err("Spellout format is unavailable\n");
814 { /* Test for ticket #7079 */
815 UNumberFormat
* dec_en
;
816 UChar groupingSep
[] = { 0 };
817 UChar numPercent
[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
818 double parseResult
= 0.0;
821 dec_en
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
822 unum_setAttribute(dec_en
, UNUM_LENIENT_PARSE
, 0);
823 unum_setSymbol(dec_en
, UNUM_GROUPING_SEPARATOR_SYMBOL
, groupingSep
, 0, &status
);
824 parseResult
= unum_parseDouble(dec_en
, numPercent
, -1, NULL
, &status
);
825 /* Without the fix in #7079, the above call will hang */
826 if ( U_FAILURE(status
) || parseResult
!= 12.0 ) {
827 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
828 myErrorName(status
), parseResult
);
830 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
835 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
836 to verify that it is taking the pure decimal path. */
838 const char *bdpattern
= "#,##0.#########";
839 const char *numInitial
= "12345678900987654321.1234567896";
840 const char *numFormatted
= "12,345,678,900,987,654,321.12345679";
841 const char *parseExpected
= "12345678900987654321.12345679";
842 int32_t resultSize
= 0;
843 int32_t parsePos
= 0; /* Output parameter for Parse operations. */
844 #define DESTCAPACITY 100
845 UChar dest
[DESTCAPACITY
];
846 char desta
[DESTCAPACITY
];
847 UFieldPosition fieldPos
= {0};
851 status
= U_ZERO_ERROR
;
852 u_uastrcpy(dest
, bdpattern
);
853 fmt
= unum_open(UNUM_PATTERN_DECIMAL
, dest
, -1, "en", NULL
/*parseError*/, &status
);
854 if (U_FAILURE(status
)) log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
856 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, NULL
, &status
);
857 if (U_FAILURE(status
)) {
858 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
860 u_austrncpy(desta
, dest
, DESTCAPACITY
);
861 if (strcmp(numFormatted
, desta
) != 0) {
862 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
863 __FILE__
, __LINE__
, numFormatted
, desta
);
865 if (strlen(numFormatted
) != resultSize
) {
866 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
867 __FILE__
, __LINE__
, strlen(numFormatted
), resultSize
);
870 /* Format with a FieldPosition parameter */
872 fieldPos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
873 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, &fieldPos
, &status
);
874 if (U_FAILURE(status
)) {
875 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
877 u_austrncpy(desta
, dest
, DESTCAPACITY
);
878 if (strcmp(numFormatted
, desta
) != 0) {
879 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
880 __FILE__
, __LINE__
, numFormatted
, desta
);
882 if (fieldPos
.beginIndex
!= 26) { /* index of "." in formatted number */
883 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
884 __FILE__
, __LINE__
, 0, fieldPos
.beginIndex
);
886 if (fieldPos
.endIndex
!= 27) {
887 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
888 __FILE__
, __LINE__
, 0, fieldPos
.endIndex
);
893 status
= U_ZERO_ERROR
;
894 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
895 resultSize
= unum_parseDecimal(fmt
, dest
, -1, NULL
, desta
, DESTCAPACITY
, &status
);
896 if (U_FAILURE(status
)) {
897 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
899 if (strcmp(parseExpected
, desta
) != 0) {
900 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
901 __FILE__
, __LINE__
, parseExpected
, desta
);
903 if (strlen(parseExpected
) != resultSize
) {
904 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
905 __FILE__
, __LINE__
, strlen(parseExpected
), resultSize
);
908 /* Parse with a parsePos parameter */
910 status
= U_ZERO_ERROR
;
911 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
912 parsePos
= 3; /* 12,345,678,900,987,654,321.12345679 */
913 /* start parsing at the the third char */
914 resultSize
= unum_parseDecimal(fmt
, dest
, -1, &parsePos
, desta
, DESTCAPACITY
, &status
);
915 if (U_FAILURE(status
)) {
916 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
918 if (strcmp(parseExpected
+2, desta
) != 0) { /* "345678900987654321.12345679" */
919 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
920 __FILE__
, __LINE__
, parseExpected
+2, desta
);
922 if (strlen(numFormatted
) != parsePos
) {
923 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
924 __FILE__
, __LINE__
, strlen(parseExpected
), parsePos
);
930 status
= U_ZERO_ERROR
;
931 /* Test invalid symbol argument */
933 int32_t badsymbolLarge
= UNUM_FORMAT_SYMBOL_COUNT
+ 1;
934 int32_t badsymbolSmall
= -1;
936 int32_t valueLength
= 10;
937 UNumberFormat
*fmt
= unum_open(UNUM_DEFAULT
, NULL
, 0, NULL
, NULL
, &status
);
938 if (U_FAILURE(status
)) {
939 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
941 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, NULL
, 0, &status
);
942 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
944 status
= U_ZERO_ERROR
;
945 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, NULL
, 0, &status
);
946 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
948 status
= U_ZERO_ERROR
;
949 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, value
, valueLength
, &status
);
950 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
952 status
= U_ZERO_ERROR
;
953 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, value
, valueLength
, &status
);
954 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
961 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
968 unum_close(spellout_def
);
970 unum_close(cur_frpattern
);
975 static void TestParseZero(void)
977 UErrorCode errorCode
= U_ZERO_ERROR
;
978 UChar input
[] = {0x30, 0}; /* Input text is decimal '0' */
979 UChar pat
[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
983 UNumberFormat
* unum
= unum_open( UNUM_DECIMAL
/*or UNUM_DEFAULT*/, NULL
, -1, NULL
, NULL
, &errorCode
);
985 UNumberFormat
* unum
= unum_open( UNUM_PATTERN_DECIMAL
/*needs pattern*/, pat
, -1, NULL
, NULL
, &errorCode
);
988 dbl
= unum_parseDouble( unum
, input
, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode
);
989 if (U_FAILURE(errorCode
)) {
990 log_data_err("Result - %s\n", u_errorName(errorCode
));
992 log_verbose("Double: %f\n", dbl
);
997 static const UChar dollars2Sym
[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
998 static const UChar dollars4Sym
[] = { 0x24,0x34,0 }; /* $4 */
999 static const UChar dollars9Sym
[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
1000 static const UChar pounds3Sym
[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
1001 static const UChar pounds5Sym
[] = { 0xA3,0x35,0 }; /* [POUND]5 */
1002 static const UChar pounds7Sym
[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
1003 static const UChar euros4Sym
[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
1004 static const UChar euros6Sym
[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
1005 static const UChar euros8Sym
[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
1006 static const UChar dollars4PluEn
[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
1007 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 */
1008 static const UChar euros8PluEn
[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
1009 static const UChar euros6PluFr
[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
1012 const char * locale
;
1013 const char * descrip
;
1014 const UChar
* currStr
;
1015 const UChar
* plurStr
;
1016 UErrorCode parsDoubExpectErr
;
1017 int32_t parsDoubExpectPos
;
1018 double parsDoubExpectVal
;
1019 UErrorCode parsCurrExpectErr
;
1020 int32_t parsCurrExpectPos
;
1021 double parsCurrExpectVal
;
1022 const char * parsCurrExpectCurr
;
1023 } ParseCurrencyItem
;
1025 static const ParseCurrencyItem parseCurrencyItems
[] = {
1026 { "en_US", "dollars2", dollars2Sym
, NULL
, U_ZERO_ERROR
, 5, 2.0, U_ZERO_ERROR
, 5, 2.0, "USD" },
1027 { "en_US", "dollars4", dollars4Sym
, dollars4PluEn
, U_ZERO_ERROR
, 2, 4.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1028 { "en_US", "dollars9", dollars9Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1029 { "en_US", "pounds3", pounds3Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1030 { "en_US", "pounds5", pounds5Sym
, pounds5PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1031 { "en_US", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1032 { "en_US", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1034 { "en_GB", "pounds3", pounds3Sym
, NULL
, U_ZERO_ERROR
, 5, 3.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1035 { "en_GB", "pounds5", pounds5Sym
, pounds5PluEn
, U_ZERO_ERROR
, 2, 5.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1036 { "en_GB", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1037 { "en_GB", "euros4", euros4Sym
, NULL
, U_PARSE_ERROR
, 4, 0.0, U_PARSE_ERROR
, 4, 0.0, "" },
1038 { "en_GB", "euros6", euros6Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1039 { "en_GB", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1040 { "en_GB", "dollars4", dollars4Sym
, dollars4PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1042 { "fr_FR", "euros4", euros4Sym
, NULL
, U_ZERO_ERROR
, 6, 4.0, U_ZERO_ERROR
, 6, 4.0, "EUR" },
1043 { "fr_FR", "euros6", euros6Sym
, euros6PluFr
, U_ZERO_ERROR
, 3, 6.0, U_ZERO_ERROR
, 3, 6.0, "EUR" },
1044 { "fr_FR", "euros8", euros8Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1045 { "fr_FR", "dollars2", dollars2Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1046 { "fr_FR", "dollars4", dollars4Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1048 { NULL
, NULL
, NULL
, NULL
, 0, 0, 0.0, 0, 0, 0.0, NULL
}
1051 static void TestParseCurrency()
1053 const ParseCurrencyItem
* itemPtr
;
1054 for (itemPtr
= parseCurrencyItems
; itemPtr
->locale
!= NULL
; ++itemPtr
) {
1055 UNumberFormat
* unum
;
1062 status
= U_ZERO_ERROR
;
1063 unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1064 if (U_SUCCESS(status
)) {
1065 status
= U_ZERO_ERROR
;
1067 parseVal
= unum_parseDouble(unum
, itemPtr
->currStr
, -1, &parsePos
, &status
);
1068 if (status
!= itemPtr
->parsDoubExpectErr
|| parsePos
!= itemPtr
->parsDoubExpectPos
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1069 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1070 itemPtr
->locale
, itemPtr
->descrip
,
1071 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectPos
, itemPtr
->parsDoubExpectVal
,
1072 u_errorName(status
), parsePos
, parseVal
);
1074 status
= U_ZERO_ERROR
;
1077 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->currStr
, -1, &parsePos
, parseCurr
, &status
);
1078 u_austrncpy(parseCurrB
, parseCurr
, 4);
1079 if (status
!= itemPtr
->parsCurrExpectErr
|| parsePos
!= itemPtr
->parsCurrExpectPos
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1080 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1081 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1082 itemPtr
->locale
, itemPtr
->descrip
,
1083 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectPos
, itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1084 u_errorName(status
), parsePos
, parseVal
, parseCurrB
);
1088 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1092 /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */
1093 if (itemPtr
->plurStr
!= NULL
) {
1094 status
= U_ZERO_ERROR
;
1095 unum
= unum_open(UNUM_CURRENCY_PLURAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1096 if (U_SUCCESS(status
)) {
1097 status
= U_ZERO_ERROR
;
1099 parseVal
= unum_parseDouble(unum
, itemPtr
->plurStr
, -1, &parsePos
, &status
);
1100 if (status
!= itemPtr
->parsDoubExpectErr
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1101 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
1102 itemPtr
->locale
, itemPtr
->descrip
,
1103 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectVal
,
1104 u_errorName(status
), parseVal
);
1106 status
= U_ZERO_ERROR
;
1109 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->plurStr
, -1, &parsePos
, parseCurr
, &status
);
1110 u_austrncpy(parseCurrB
, parseCurr
, 4);
1111 if (status
!= itemPtr
->parsCurrExpectErr
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1112 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1113 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1114 itemPtr
->locale
, itemPtr
->descrip
,
1115 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1116 u_errorName(status
), parseVal
, parseCurrB
);
1120 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1128 const char * testname
;
1129 const char * locale
;
1131 const UChar
* source
;
1138 static const UChar ustr_zh50d
[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1139 static const UChar ustr_zh05a
[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1140 static const UChar ustr_zh05d
[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1142 static const NumParseTestItem altnumParseTests
[] = {
1143 /* name loc lenent src start val end status */
1144 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1145 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1146 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1147 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1150 static void TestParseAltNum(void)
1152 const NumParseTestItem
* testPtr
;
1153 for (testPtr
= altnumParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1154 UErrorCode status
= U_ZERO_ERROR
;
1155 int32_t value
, position
= testPtr
->startPos
;
1156 UNumberFormat
*nf
= unum_open(UNUM_DECIMAL
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1157 if (U_FAILURE(status
)) {
1158 log_err_status(status
, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1161 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1162 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1163 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1164 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1165 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1166 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1167 value
, position
, myErrorName(status
) );
1173 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1174 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1175 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1176 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1177 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1178 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1179 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent-vingt-trois */
1180 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1181 static const UChar ustr_zh50s
[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1182 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1183 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1184 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1186 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1188 static const NumParseTestItem spelloutParseTests
[] = {
1189 /* name loc lenent src start val end status */
1190 { "en0", "en", FALSE
, ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
1191 { "en0", "en", FALSE
, ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
1192 { "en0", "ja", FALSE
, ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
1193 #if NUMERIC_STRINGS_NOT_PARSEABLE
1194 { "123", "en", FALSE
, ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
1196 { "123", "en", FALSE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1198 { "123L", "en", TRUE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1199 { "en123", "en", FALSE
, ustr_en123
, 0, 123, 24, U_ZERO_ERROR
},
1200 { "en123", "en", FALSE
, ustr_en123
, 12, 23, 24, U_ZERO_ERROR
},
1201 { "en123", "fr", FALSE
, ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
1202 { "fr123", "fr", FALSE
, ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
1203 { "fr123", "fr", FALSE
, ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
1204 { "fr123", "en", FALSE
, ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
1205 { "ja123", "ja", FALSE
, ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
1206 { "ja123", "ja", FALSE
, ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
1207 { "ja123", "fr", FALSE
, ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
1208 { "zh,50s", "zh", FALSE
, ustr_zh50s
, 0, 50, 2, U_ZERO_ERROR
},
1209 #if NUMERIC_STRINGS_NOT_PARSEABLE
1210 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 5, 1, U_ZERO_ERROR
},
1211 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1212 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 0, 1, U_ZERO_ERROR
},
1214 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1215 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1216 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1218 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1219 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1220 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1221 { "zh,50dL","zh", TRUE
, ustr_zh50d
, 0, 5, 1, U_ZERO_ERROR
},
1222 { "zh,05aL","zh", TRUE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1223 { "zh,05dL","zh", TRUE
, ustr_zh05d
, 0, 0, 1, U_ZERO_ERROR
},
1224 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1227 static void TestSpelloutNumberParse()
1229 const NumParseTestItem
* testPtr
;
1230 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1231 UErrorCode status
= U_ZERO_ERROR
;
1232 int32_t value
, position
= testPtr
->startPos
;
1233 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1234 if (U_FAILURE(status
)) {
1235 log_err_status(status
, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1238 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1239 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1240 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1241 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1242 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1243 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1244 value
, position
, myErrorName(status
) );
1250 static void TestSignificantDigits()
1253 int32_t resultlengthneeded
;
1254 int32_t resultlength
;
1255 UErrorCode status
= U_ZERO_ERROR
;
1256 UChar
*result
= NULL
;
1258 double d
= 123456.789;
1260 u_uastrcpy(temp
, "###0.0#");
1261 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, NULL
, NULL
,&status
);
1262 if (U_FAILURE(status
)) {
1263 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1266 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1267 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
1269 u_uastrcpy(temp
, "123457");
1271 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
1272 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1274 status
=U_ZERO_ERROR
;
1275 resultlength
=resultlengthneeded
+1;
1276 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1277 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
1279 if(U_FAILURE(status
))
1281 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1284 if(u_strcmp(result
, temp
)==0)
1285 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1287 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1292 static void TestSigDigRounding()
1294 UErrorCode status
= U_ZERO_ERROR
;
1295 UChar expected
[128];
1302 fmt
=unum_open(UNUM_DECIMAL
, NULL
, 0, NULL
/* "en_US"*/, NULL
, &status
);
1303 if (U_FAILURE(status
)) {
1304 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1307 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, FALSE
);
1308 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1309 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2);
1310 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1312 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_UP
);
1313 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, 20.0);
1315 (void)unum_formatDouble(fmt
, d
, result
, sizeof(result
) / sizeof(result
[0]), NULL
, &status
);
1316 if(U_FAILURE(status
))
1318 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1322 u_uastrcpy(expected
, "140");
1323 if(u_strcmp(result
, expected
)!=0)
1324 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1
, result
), u_austrcpy(temp2
, expected
) );
1329 static void TestNumberFormatPadding()
1334 UErrorCode status
=U_ZERO_ERROR
;
1335 int32_t resultlength
;
1336 int32_t resultlengthneeded
;
1337 UNumberFormat
*pattern
;
1339 double d
= -10456.37;
1340 UFieldPosition pos1
;
1343 /* create a number format using unum_openPattern(....)*/
1344 log_verbose("\nTesting unum_openPattern() with padding\n");
1345 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
1346 status
=U_ZERO_ERROR
;
1347 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
1348 if(U_SUCCESS(status
))
1350 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );
1354 unum_close(pattern
);
1357 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1358 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
1359 status
=U_ZERO_ERROR
;
1360 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
1361 if(U_FAILURE(status
))
1363 log_err_status(status
, "error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
1366 log_verbose("Pass: padding unum_openPattern() works fine\n");
1368 /*test for unum_toPattern()*/
1369 log_verbose("\nTesting padding unum_toPattern()\n");
1371 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
1372 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1374 status
=U_ZERO_ERROR
;
1375 resultlength
=resultlengthneeded
+1;
1376 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1377 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
1379 if(U_FAILURE(status
))
1381 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
1385 if(u_strcmp(result
, temp1
)!=0)
1386 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
1388 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1391 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1392 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
1394 pos1
.field
= UNUM_FRACTION_FIELD
;
1395 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
1396 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1398 status
=U_ZERO_ERROR
;
1399 resultlength
=resultlengthneeded
+1;
1400 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1401 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
1403 if(U_FAILURE(status
))
1405 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
1409 if(u_strcmp(result
, temp1
)==0)
1410 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1412 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1413 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
1414 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1416 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1417 pos1
.beginIndex
, pos1
.endIndex
);
1420 /* Testing unum_parse() and unum_parseDouble() */
1421 log_verbose("\nTesting padding unum_parseDouble()\n");
1423 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
1424 if(U_FAILURE(status
))
1426 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
1430 log_err("Fail: Error in padding parsing\n");
1432 log_verbose("Pass: padding parsing successful\n");
1437 unum_close(pattern
);
1441 withinErr(double a
, double b
, double err
) {
1442 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
1445 static void TestInt64Format() {
1449 UErrorCode status
= U_ZERO_ERROR
;
1450 const double doubleInt64Max
= (double)U_INT64_MAX
;
1451 const double doubleInt64Min
= (double)U_INT64_MIN
;
1452 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
1458 /* create a number format using unum_openPattern(....) */
1459 log_verbose("\nTesting Int64Format\n");
1460 u_uastrcpy(temp1
, "#.#E0");
1461 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), NULL
, NULL
, &status
);
1462 if(U_FAILURE(status
)) {
1463 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status
));
1465 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1466 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1467 if (U_FAILURE(status
)) {
1468 log_err("error in unum_format(): %s\n", myErrorName(status
));
1470 log_verbose("format int64max: '%s'\n", result
);
1472 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1473 if (status
!= U_INVALID_FORMAT_ERROR
) {
1474 log_err("parse didn't report error: %s\n", myErrorName(status
));
1475 } else if (val32
!= INT32_MAX
) {
1476 log_err("parse didn't pin return value, got: %d\n", val32
);
1479 status
= U_ZERO_ERROR
;
1481 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1482 if (U_FAILURE(status
)) {
1483 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1484 } else if (val64
!= U_INT64_MAX
) {
1485 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1488 status
= U_ZERO_ERROR
;
1490 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1491 if (U_FAILURE(status
)) {
1492 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1493 } else if (valDouble
!= doubleInt64Max
) {
1494 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1498 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1499 if (U_FAILURE(status
)) {
1500 log_err("error in unum_format(): %s\n", myErrorName(status
));
1502 log_verbose("format int64min: '%s'\n", result
);
1504 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1505 if (status
!= U_INVALID_FORMAT_ERROR
) {
1506 log_err("parse didn't report error: %s\n", myErrorName(status
));
1507 } else if (val32
!= INT32_MIN
) {
1508 log_err("parse didn't pin return value, got: %d\n", val32
);
1511 status
= U_ZERO_ERROR
;
1513 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1514 if (U_FAILURE(status
)) {
1515 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1516 } else if (val64
!= U_INT64_MIN
) {
1517 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1520 status
= U_ZERO_ERROR
;
1522 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1523 if (U_FAILURE(status
)) {
1524 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1525 } else if (valDouble
!= doubleInt64Min
) {
1526 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1530 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1531 if (U_FAILURE(status
)) {
1532 log_err("error in unum_format(): %s\n", myErrorName(status
));
1534 log_verbose("format doubleBig: '%s'\n", result
);
1536 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1537 if (status
!= U_INVALID_FORMAT_ERROR
) {
1538 log_err("parse didn't report error: %s\n", myErrorName(status
));
1539 } else if (val32
!= INT32_MAX
) {
1540 log_err("parse didn't pin return value, got: %d\n", val32
);
1543 status
= U_ZERO_ERROR
;
1545 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1546 if (status
!= U_INVALID_FORMAT_ERROR
) {
1547 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1548 } else if (val64
!= U_INT64_MAX
) {
1549 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1552 status
= U_ZERO_ERROR
;
1554 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1555 if (U_FAILURE(status
)) {
1556 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1557 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1558 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1562 u_uastrcpy(result
, "5.06e-27");
1564 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1565 if (U_FAILURE(status
)) {
1566 log_err("parseDouble() returned error: %s\n", myErrorName(status
));
1567 } else if (!withinErr(valDouble
, 5.06e-27, 1e-15)) {
1568 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble
);
1575 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1578 int32_t BUFSIZE
= sizeof(buffer
)/sizeof(buffer
[0]);
1580 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1584 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1585 UErrorCode status
= U_ZERO_ERROR
;
1586 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1587 if (U_FAILURE(status
)) {
1588 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1590 u_austrcpy(temp
, buffer
);
1591 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1595 /* check APIs now */
1597 UErrorCode status
= U_ZERO_ERROR
;
1599 u_uastrcpy(buffer
, "#,##0.0#");
1600 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1601 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1602 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1607 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1608 log_verbose("lenient: 0x%x\n", isLenient
);
1609 if (isLenient
!= FALSE
) {
1610 log_err("didn't expect lenient value: %d\n", isLenient
);
1613 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1614 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1615 if (isLenient
!= TRUE
) {
1616 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1622 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1624 log_err("didn't expect double attribute\n");
1626 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1627 if ((val
== -1) == isDecimal
) {
1628 log_err("didn't expect -1 rounding increment\n");
1630 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1631 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1632 if (isDecimal
&& (val2
- val
!= .5)) {
1633 log_err("set rounding increment had no effect on decimal format");
1638 UErrorCode status
= U_ZERO_ERROR
;
1639 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1640 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1641 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1643 if (U_SUCCESS(status
)) {
1644 u_austrcpy(temp
, buffer
);
1645 log_verbose("default ruleset: '%s'\n", temp
);
1648 status
= U_ZERO_ERROR
;
1649 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1650 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1651 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1653 if (U_SUCCESS(status
)) {
1654 u_austrcpy(temp
, buffer
);
1655 log_verbose("public rulesets: '%s'\n", temp
);
1657 /* set the default ruleset to the first one found, and retry */
1660 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1663 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1664 if (U_FAILURE(status
)) {
1665 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1667 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1668 if (U_FAILURE(status
)) {
1669 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1670 } else if (len2
!= i
) {
1671 u_austrcpy(temp
, buffer
);
1672 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1674 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1675 status
= U_ZERO_ERROR
;
1676 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1677 if (U_FAILURE(status
)) {
1678 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1680 u_austrcpy(temp
, buffer
);
1681 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1692 UErrorCode status
= U_ZERO_ERROR
;
1693 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1694 if (U_SUCCESS(status
)) {
1695 u_austrcpy(temp
, buffer
);
1696 log_verbose("pattern: '%s'\n", temp
);
1697 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1698 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1700 log_verbose("pattern too long to display\n");
1705 UErrorCode status
= U_ZERO_ERROR
;
1706 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1707 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1708 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1711 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1712 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1713 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1718 static void TestNonExistentCurrency() {
1719 UNumberFormat
*format
;
1720 UErrorCode status
= U_ZERO_ERROR
;
1721 UChar currencySymbol
[8];
1722 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1724 /* Get a non-existent currency and make sure it returns the correct currency code. */
1725 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1726 if (format
== NULL
|| U_FAILURE(status
)) {
1727 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status
));
1730 unum_getSymbol(format
,
1731 UNUM_CURRENCY_SYMBOL
,
1733 sizeof(currencySymbol
)/sizeof(currencySymbol
[0]),
1735 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1736 log_err("unum_open set the currency to QQQ\n");
1742 static void TestRBNFFormat() {
1746 UChar tempUChars
[512];
1747 UNumberFormat
*formats
[5];
1748 int COUNT
= sizeof(formats
)/sizeof(formats
[0]);
1751 for (i
= 0; i
< COUNT
; ++i
) {
1756 status
= U_ZERO_ERROR
;
1757 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1758 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1759 if (U_FAILURE(status
)) {
1760 log_err_status(status
, "unable to open decimal pattern -> %s\n", u_errorName(status
));
1764 status
= U_ZERO_ERROR
;
1765 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1766 if (U_FAILURE(status
)) {
1767 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1771 status
= U_ZERO_ERROR
;
1772 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1773 if (U_FAILURE(status
)) {
1774 log_err_status(status
, "unable to open ordinal -> %s\n", u_errorName(status
));
1778 status
= U_ZERO_ERROR
;
1779 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1780 if (U_FAILURE(status
)) {
1781 log_err_status(status
, "unable to open duration %s\n", u_errorName(status
));
1785 status
= U_ZERO_ERROR
;
1789 "x.x: << point >>;\n"
1790 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1791 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1792 "seventeen; eighteen; nineteen;\n"
1793 "20: twenty[->>];\n"
1794 "30: thirty[->>];\n"
1798 "70: seventy[->>];\n"
1799 "80: eighty[->>];\n"
1800 "90: ninety[->>];\n"
1802 u_uastrcpy(tempUChars
,
1805 "20: twenty[ and change];\n"
1806 "30: thirty[ and change];\n"
1807 "40: forty[ and change];\n"
1808 "50: fifty[ and change];\n"
1809 "60: sixty[ and change];\n"
1810 "70: seventy[ and change];\n"
1811 "80: eighty[ and change];\n"
1812 "90: ninety[ and change];\n"
1816 "x.x: << point something;\n"
1818 "20: some reasonable number;\n"
1819 "100: some substantial number;\n"
1820 "100,000,000: some huge number;\n");
1821 /* This is to get around some compiler warnings about char * string length. */
1822 u_strcat(pat
, tempUChars
);
1823 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1824 if (U_FAILURE(status
)) {
1825 log_err_status(status
, "unable to open rulebased pattern -> %s\n", u_errorName(status
));
1827 if (U_FAILURE(status
)) {
1828 log_err_status(status
, "Something failed with %s\n", u_errorName(status
));
1832 for (i
= 0; i
< COUNT
; ++i
) {
1833 log_verbose("\n\ntesting format %d\n", i
);
1834 test_fmt(formats
[i
], (UBool
)(i
== 0));
1837 #define FORMAT_BUF_CAPACITY 64
1839 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1841 double nanvalue
= uprv_getNaN();
1842 status
= U_ZERO_ERROR
;
1843 len
= unum_formatDouble(formats
[1], nanvalue
, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1844 if (U_FAILURE(status
)) {
1845 log_err_status(status
, "unum_formatDouble NAN failed with %s\n", u_errorName(status
));
1847 UChar nansym
[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1848 if ( len
!= 3 || u_strcmp(fmtbuf
, nansym
) != 0 ) {
1849 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1854 for (i
= 0; i
< COUNT
; ++i
) {
1855 unum_close(formats
[i
]);
1859 static void TestCurrencyRegression(void) {
1861 I've found a case where unum_parseDoubleCurrency is not doing what I
1862 expect. The value I pass in is $1234567890q123460000.00 and this
1863 returns with a status of zero error & a parse pos of 22 (I would
1864 expect a parse error at position 11).
1866 I stepped into DecimalFormat::subparse() and it looks like it parses
1867 the first 10 digits and then stops parsing at the q but doesn't set an
1868 error. Then later in DecimalFormat::parse() the value gets crammed
1869 into a long (which greatly truncates the value).
1871 This is very problematic for me 'cause I try to remove chars that are
1872 invalid but this allows my users to enter bad chars and truncates
1882 UErrorCode status
= U_ZERO_ERROR
;
1883 const int32_t expected
= 11;
1886 u_uastrcpy(buf
, "$1234567890q643210000.00");
1887 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1889 if(U_FAILURE(status
)) {
1890 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status
));
1894 status
= U_ZERO_ERROR
; /* so we can test it later. */
1897 d
= unum_parseDoubleCurrency(cur
,
1900 &pos
, /* 0 = start */
1904 u_austrcpy(acurrency
, currency
);
1906 if(U_FAILURE(status
) || (pos
!= expected
)) {
1907 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1908 expected
, d
, u_errorName(status
), pos
, acurrency
);
1910 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
1916 static void TestTextAttributeCrash(void) {
1917 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
1918 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1919 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1921 UErrorCode status
= U_ZERO_ERROR
;
1922 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
1923 if (U_FAILURE(status
)) {
1924 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status
));
1927 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
1929 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1930 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1932 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
1933 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
1934 if (U_FAILURE(status
)) {
1935 log_err("FAILED 2\n"); exit(1);
1937 log_verbose("attempting to format...\n");
1938 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
1939 if (U_FAILURE(status
) || 64 < used
) {
1940 log_err("Failed formatting %s\n", u_errorName(status
));
1943 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
1944 log_err("Didn't get expected negative result\n");
1946 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
1947 if (U_FAILURE(status
) || 64 < used
) {
1948 log_err("Failed formatting %s\n", u_errorName(status
));
1951 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
1952 log_err("Didn't get expected positive result\n");
1957 static void TestNBSPPatternRtNum(const char *testcase
, UNumberFormat
*nf
, double myNumber
) {
1958 UErrorCode status
= U_ZERO_ERROR
;
1961 double aNumber
= -1.0;
1962 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
1963 log_verbose("%s: formatted %.2f into %s\n", testcase
, myNumber
, u_austrcpy(tmpbuf
, myString
));
1964 if(U_FAILURE(status
)) {
1965 log_err("%s: failed format of %.2g with %s\n", testcase
, myNumber
, u_errorName(status
));
1968 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
1969 if(U_FAILURE(status
)) {
1970 log_err("%s: failed parse with %s\n", testcase
, u_errorName(status
));
1973 if(uprv_fabs(aNumber
-myNumber
)>.001) {
1974 log_err("FAIL: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1976 log_verbose("PASS: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1980 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
1981 TestNBSPPatternRtNum(testcase
, nf
, 12345.);
1982 TestNBSPPatternRtNum(testcase
, nf
, -12345.);
1985 static void TestNBSPInPattern(void) {
1986 UErrorCode status
= U_ZERO_ERROR
;
1987 UNumberFormat
* nf
= NULL
;
1988 const char *testcase
;
1991 testcase
="ar_AE UNUM_CURRENCY";
1992 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
1993 if(U_FAILURE(status
) || nf
== NULL
) {
1994 log_data_err("%s: unum_open failed with %s (Are you missing data?)\n", testcase
, u_errorName(status
));
1997 TestNBSPPatternRT(testcase
, nf
);
1999 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
2001 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
2003 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
2004 u_unescape(SPECIAL_PATTERN
, pat
, sizeof(pat
)/sizeof(pat
[0]));
2005 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
2006 if(U_FAILURE(status
)) {
2007 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
2009 TestNBSPPatternRT(testcase
, nf
);
2011 #undef SPECIAL_PATTERN
2013 unum_close(nf
); status
= U_ZERO_ERROR
;
2015 testcase
="ar_AE UNUM_DECIMAL";
2016 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
2017 if(U_FAILURE(status
)) {
2018 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2020 TestNBSPPatternRT(testcase
, nf
);
2021 unum_close(nf
); status
= U_ZERO_ERROR
;
2023 testcase
="ar_AE UNUM_PERCENT";
2024 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
2025 if(U_FAILURE(status
)) {
2026 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2028 TestNBSPPatternRT(testcase
, nf
);
2029 unum_close(nf
); status
= U_ZERO_ERROR
;
2034 static void TestCloneWithRBNF(void) {
2035 UChar pattern
[1024];
2037 UErrorCode status
= U_ZERO_ERROR
;
2039 UChar buffer_cloned
[256];
2042 UNumberFormat
*pform_cloned
;
2043 UNumberFormat
*pform
;
2047 "0.x: >%%millis-only>;\n"
2048 "x.0: <%%duration<;\n"
2049 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2050 "-x: ->>;%%millis-only:\n"
2051 "1000: 00:00.<%%millis<;\n"
2053 "1000: .<%%millis<;\n"
2057 "0: =%%seconds-only=;\n"
2058 "60: =%%min-sec=;\n"
2059 "3600: =%%hr-min-sec=;\n"
2060 "86400/86400: <%%ddaayyss<[, >>];\n"
2061 "%%durationwithmillis:\n"
2062 "0: =%%seconds-only=;\n"
2063 "60: =%%min-sec=;\n"
2064 "3600: =%%hr-min-sec=;\n"
2065 "86400/86400: <%%ddaayyss<, >>;\n");
2075 "3600/60: <0<:>>>;\n"
2081 /* This is to get around some compiler warnings about char * string length. */
2082 u_strcat(pattern
, pat2
);
2084 pform
= unum_open(UNUM_PATTERN_RULEBASED
, pattern
, -1, "en_US", NULL
, &status
);
2085 unum_formatDouble(pform
, 3600, buffer
, 256, NULL
, &status
);
2087 pform_cloned
= unum_clone(pform
,&status
);
2088 unum_formatDouble(pform_cloned
, 3600, buffer_cloned
, 256, NULL
, &status
);
2091 unum_close(pform_cloned
);
2093 if (u_strcmp(buffer
,buffer_cloned
)) {
2094 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
));
2097 #endif /* #if !UCONFIG_NO_FORMATTING */