1 /********************************************************************
3 * Copyright (c) 1997-2010, 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 TestParseAltNum(void);
44 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
46 void addNumForTest(TestNode
** root
)
48 TESTCASE(TestNumberFormat
);
49 TESTCASE(TestSpelloutNumberParse
);
50 TESTCASE(TestSignificantDigits
);
51 TESTCASE(TestSigDigRounding
);
52 TESTCASE(TestNumberFormatPadding
);
53 TESTCASE(TestInt64Format
);
54 TESTCASE(TestNonExistentCurrency
);
55 TESTCASE(TestCurrencyRegression
);
56 TESTCASE(TestTextAttributeCrash
);
57 TESTCASE(TestRBNFFormat
);
58 TESTCASE(TestNBSPInPattern
);
59 TESTCASE(TestInt64Parse
);
60 TESTCASE(TestParseZero
);
61 TESTCASE(TestParseAltNum
);
64 /** copy src to dst with unicode-escapes for values < 0x20 and > 0x7e, null terminate if possible */
65 static int32_t ustrToAstr(const UChar
* src
, int32_t srcLength
, char* dst
, int32_t dstLength
) {
66 static const char hex
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
69 const char *e
= p
+ dstLength
;
75 srcLength
= (int32_t)(s
- src
);
77 while (p
< e
&& --srcLength
>= 0) {
79 if (c
== 0xd || c
== 0xa || c
== 0x9 || (c
>= 0x20 && c
<= 0x7e)) {
80 *p
++ = (char) c
& 0x7f;
81 } else if (e
- p
>= 6) {
84 *p
++ = hex
[(c
>> 12) & 0xf];
85 *p
++ = hex
[(c
>> 8) & 0xf];
86 *p
++ = hex
[(c
>> 4) & 0xf];
95 return (int32_t)(p
- dst
);
98 /* test Parse int 64 */
100 static void TestInt64Parse()
103 UErrorCode st
= U_ZERO_ERROR
;
104 UErrorCode
* status
= &st
;
106 const char* st1
= "009223372036854775808";
115 u_charsToUChars(st1
, text
, size
);
116 nf
= unum_open(UNUM_DEFAULT
, NULL
, -1, NULL
, NULL
, status
);
118 if(U_FAILURE(*status
))
120 log_data_err("Error in unum_open() %s \n", myErrorName(*status
));
124 log_verbose("About to test unum_parseInt64() with out of range number\n");
126 a
= unum_parseInt64(nf
, text
, size
, 0, status
);
129 if(!U_FAILURE(*status
))
131 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status
));
135 log_verbose("unum_parseInt64() successful\n");
142 /* test Number Format API */
143 static void TestNumberFormat()
154 int32_t resultlength
;
155 int32_t resultlengthneeded
;
159 double d
= -10456.37;
160 double a
= 1234.56, a1
= 1235.0;
161 int32_t l
= 100000000;
167 UNumberFormatAttribute attr
;
168 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
170 UErrorCode status
=U_ZERO_ERROR
;
171 UNumberFormatStyle style
= UNUM_DEFAULT
;
172 UNumberFormat
*pattern
;
173 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
174 *cur_frpattern
, *myclone
, *spellout_def
;
176 /* Testing unum_open() with various Numberformat styles and locales*/
177 status
= U_ZERO_ERROR
;
178 log_verbose("Testing unum_open() with default style and locale\n");
179 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
181 /* Might as well pack it in now if we can't even get a default NumberFormat... */
182 if(U_FAILURE(status
))
184 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status
));
188 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
189 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
190 if(U_FAILURE(status
))
191 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
193 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
195 /* Can't hardcode the result to assume the default locale is "en_US". */
196 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
197 if(U_FAILURE(status
))
198 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
199 myErrorName(status
) );
201 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
202 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
203 if(U_FAILURE(status
))
204 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
205 myErrorName(status
));
207 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
209 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
210 if(U_FAILURE(status
))
211 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
213 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
214 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
215 if(U_FAILURE(status
))
216 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
218 log_verbose("\nTesting unum_open(spellout, NULL, status)");
220 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
221 if(U_FAILURE(status
))
222 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
224 /* Testing unum_clone(..) */
225 log_verbose("\nTesting unum_clone(fmt, status)");
226 status
= U_ZERO_ERROR
;
227 myclone
= unum_clone(def
,&status
);
228 if(U_FAILURE(status
))
229 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
232 log_verbose("unum_clone() successful\n");
235 /*Testing unum_getAvailable() and unum_countAvailable()*/
236 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
237 numlocales
=unum_countAvailable();
239 log_err("error in countAvailable");
241 log_verbose("unum_countAvialable() successful\n");
242 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
244 for(i
=0;i
<numlocales
;i
++)
246 log_verbose("%s\n", unum_getAvailable(i
));
247 if (unum_getAvailable(i
) == 0)
248 log_err("No locale for which number formatting patterns are applicable\n");
250 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
254 /*Testing unum_format() and unum_formatdouble()*/
255 u_uastrcpy(temp1
, "$100,000,000.00");
257 log_verbose("\nTesting unum_format() \n");
259 pos1
.field
= 0; /* Integer Section */
260 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
261 if(status
==U_BUFFER_OVERFLOW_ERROR
)
264 resultlength
=resultlengthneeded
+1;
265 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
266 /* for (i = 0; i < 100000; i++) */
268 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
272 if(U_FAILURE(status
))
274 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
276 if(u_strcmp(result
, temp1
)==0)
277 log_verbose("Pass: Number formatting using unum_format() successful\n");
279 log_err("Fail: Error in number Formatting using unum_format()\n");
280 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
281 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
283 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
284 pos1
.beginIndex
, pos1
.endIndex
);
289 log_verbose("\nTesting unum_formatDouble()\n");
290 u_uastrcpy(temp1
, "($10,456.37)");
292 pos2
.field
= 1; /* Fractional Section */
293 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
294 if(status
==U_BUFFER_OVERFLOW_ERROR
)
297 resultlength
=resultlengthneeded
+1;
298 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
299 /* for (i = 0; i < 100000; i++) */
301 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
304 if(U_FAILURE(status
))
306 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
308 if(result
&& u_strcmp(result
, temp1
)==0)
309 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
311 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
312 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
313 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
315 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
316 pos1
.beginIndex
, pos1
.endIndex
);
319 /* Testing unum_parse() and unum_parseDouble() */
320 log_verbose("\nTesting unum_parseDouble()\n");
321 /* for (i = 0; i < 100000; i++)*/
325 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
328 log_err("result is NULL\n");
330 if(U_FAILURE(status
))
332 log_err("parse failed. The error is : %s\n", myErrorName(status
));
336 log_err("Fail: Error in parsing\n");
338 log_verbose("Pass: parsing successful\n");
344 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
345 log_verbose("\nTesting unum_formatDoubleCurrency\n");
346 u_uastrcpy(temp1
, "Y1,235");
347 temp1
[0] = 0xA5; /* Yen sign */
348 u_uastrcpy(temp
, "JPY");
350 pos2
.field
= 0; /* integer part */
351 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
352 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
354 resultlength
=resultlengthneeded
+1;
355 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
356 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
358 if (U_FAILURE(status
)) {
359 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
361 if (result
&& u_strcmp(result
, temp1
)==0) {
362 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
364 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
366 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
367 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
369 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
370 pos1
.beginIndex
, pos1
.endIndex
);
373 log_verbose("\nTesting unum_parseDoubleCurrency\n");
375 if (result
== NULL
) {
376 log_err("result is NULL\n");
379 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
380 if (U_FAILURE(status
)) {
381 log_err("parse failed. The error is : %s\n", myErrorName(status
));
383 /* Note: a==1234.56, but on parse expect a1=1235.0 */
385 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
387 log_verbose("Pass: parsed currency ammount successfully\n");
389 if (u_strcmp(temp2
, temp
)==0) {
390 log_verbose("Pass: parsed correct currency\n");
392 log_err("Fail: parsed incorrect currency\n");
400 /* performance testing */
401 u_uastrcpy(temp1
, "$462.12345");
402 resultlength
=u_strlen(temp1
);
403 /* for (i = 0; i < 100000; i++) */
406 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
408 if(U_FAILURE(status
))
410 log_err("parse failed. The error is : %s\n", myErrorName(status
));
414 * Note: "for strict standard conformance all operations and constants are now supposed to be
415 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
420 log_err("Fail: Error in parsing\n");
422 log_verbose("Pass: parsing successful\n");
426 u_uastrcpy(temp1
, "($10,456.3E1])");
428 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
429 if(U_SUCCESS(status
))
431 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
435 log_verbose("\nTesting unum_format()\n");
439 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
440 if(status
==U_BUFFER_OVERFLOW_ERROR
)
443 resultlength
=resultlengthneeded
+1;
444 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
445 /* for (i = 0; i < 100000; i++)*/
447 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
450 if(U_FAILURE(status
))
452 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
456 log_verbose("\nTesting unum_parse()\n");
457 /* for (i = 0; i < 100000; i++) */
460 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
462 if(U_FAILURE(status
))
464 log_err("parse failed. The error is : %s\n", myErrorName(status
));
468 log_err("Fail: Error in parsing\n");
470 log_verbose("Pass: parsing successful\n");
474 /* create a number format using unum_openPattern(....)*/
475 log_verbose("\nTesting unum_openPattern()\n");
476 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
477 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
478 if(U_FAILURE(status
))
480 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
483 log_verbose("Pass: unum_openPattern() works fine\n");
485 /*test for unum_toPattern()*/
486 log_verbose("\nTesting unum_toPattern()\n");
488 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
489 if(status
==U_BUFFER_OVERFLOW_ERROR
)
492 resultlength
=resultlengthneeded
+1;
493 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
494 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
496 if(U_FAILURE(status
))
498 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
502 if(u_strcmp(result
, temp1
)!=0)
503 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
505 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
509 /*Testing unum_getSymbols() and unum_setSymbols()*/
510 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
511 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
513 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
514 if(status
==U_BUFFER_OVERFLOW_ERROR
)
517 resultlength
=resultlengthneeded
+1;
518 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
519 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
521 if(U_FAILURE(status
))
523 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
527 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
528 if(U_FAILURE(status
))
530 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
535 /*getting the symbols of cur_def */
536 /*set the symbols of cur_frpattern to cur_def */
537 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
539 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
540 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
541 if(U_FAILURE(status
))
543 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
547 /*format to check the result */
549 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
550 if(status
==U_BUFFER_OVERFLOW_ERROR
)
553 resultlength
=resultlengthneeded
+1;
554 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
555 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
557 if(U_FAILURE(status
))
559 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
562 if(U_FAILURE(status
)){
563 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
565 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
567 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
569 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
570 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
571 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
573 log_err("Fail: error in getting symbols\n");
576 log_verbose("Pass: get and set symbols successful\n");
579 /*format and check with the previous result */
582 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
583 if(status
==U_BUFFER_OVERFLOW_ERROR
)
586 resultlength
=resultlengthneeded
+1;
587 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
589 if(U_FAILURE(status
))
591 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
594 * This test fails because we have not called unum_applyPattern().
595 * Currently, such an applyPattern() does not exist on the C API, and
596 * we have jitterbug 411 for it.
597 * Since it is close to the 1.5 release, I (markus) am disabling this test just
598 * for this release (I added the test itself only last week).
599 * For the next release, we need to fix this.
600 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
602 if(u_strcmp(result
, temp1
) != 0) {
603 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
611 /* Testing unum_get/setSymbol() */
612 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
613 symbol
[0] = (UChar
)(0x41 + i
);
614 symbol
[1] = (UChar
)(0x61 + i
);
615 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
616 if(U_FAILURE(status
)) {
617 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
621 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
622 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
623 if(U_FAILURE(status
)) {
624 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
627 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
628 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
631 /*try getting from a bogus symbol*/
632 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
633 if(U_SUCCESS(status
)){
634 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
636 if(U_FAILURE(status
)){
637 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
638 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
643 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
644 log_verbose("\nTesting getting and setting text attributes\n");
646 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
647 if(U_FAILURE(status
))
649 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
651 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
652 if(U_FAILURE(status
))
654 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
656 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
657 if(U_FAILURE(status
))
659 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
661 if(u_strcmp(suffix
,temp
)!=0)
662 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
664 log_verbose("Pass: setting and getting suffix works fine\n");
665 /*set it back to normal */
666 u_uastrcpy(temp
,"$");
667 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
669 /*checking some more text setter conditions */
670 u_uastrcpy(prefix
, "+");
671 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
672 if(U_FAILURE(status
))
674 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
676 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
677 if(U_FAILURE(status
))
679 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
682 if(u_strcmp(prefix
, temp
)!=0)
683 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
685 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
687 u_uastrcpy(prefix
, "+");
688 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
689 if(U_FAILURE(status
))
691 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
693 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
694 if(U_FAILURE(status
))
696 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
698 if(u_strcmp(prefix
, temp
)!=0)
699 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
701 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
703 u_uastrcpy(suffix
, "+");
704 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
705 if(U_FAILURE(status
))
707 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
710 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
711 if(U_FAILURE(status
))
713 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
715 if(u_strcmp(suffix
, temp
)!=0)
716 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
718 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
720 u_uastrcpy(suffix
, "++");
721 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
722 if(U_FAILURE(status
))
724 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
727 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
728 if(U_FAILURE(status
))
730 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
732 if(u_strcmp(suffix
, temp
)!=0)
733 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
735 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
737 /*Testing unum_getAttribute and unum_setAttribute() */
738 log_verbose("\nTesting get and set Attributes\n");
739 attr
=UNUM_GROUPING_SIZE
;
740 newvalue
=unum_getAttribute(def
, attr
);
742 unum_setAttribute(def
, attr
, newvalue
);
743 if(unum_getAttribute(def
,attr
)!=2)
744 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
746 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
748 attr
=UNUM_MULTIPLIER
;
749 newvalue
=unum_getAttribute(def
, attr
);
751 unum_setAttribute(def
, attr
, newvalue
);
752 if(unum_getAttribute(def
,attr
) != 8)
753 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
755 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
757 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
758 newvalue
=unum_getAttribute(def
, attr
);
760 unum_setAttribute(def
, attr
, newvalue
);
761 if(unum_getAttribute(def
,attr
) != 2)
762 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
764 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
766 /*testing set and get Attributes extensively */
767 log_verbose("\nTesting get and set attributes extensively\n");
768 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
770 newvalue
=unum_getAttribute(fr
, attr
);
771 unum_setAttribute(def
, attr
, newvalue
);
772 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
773 log_err("error in setting and getting attributes\n");
775 log_verbose("Pass: attributes set and retrieved successfully\n");
778 /*testing spellout format to make sure we can use it successfully.*/
779 log_verbose("\nTesting spellout format\n");
782 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
783 for (i
= 0; i
< LENGTH(values
); ++i
) {
786 int32_t value
= values
[i
];
787 status
= U_ZERO_ERROR
;
788 len
= unum_format(spellout_def
, value
, buffer
, LENGTH(buffer
), NULL
, &status
);
789 if(U_FAILURE(status
)) {
790 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
795 ustrToAstr(buffer
, len
, logbuf
, LENGTH(logbuf
));
796 log_verbose("formatted %d as '%s', length: %d\n", value
, logbuf
, len
);
798 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
799 if (U_FAILURE(status
)) {
800 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
801 } else if (parseResult
!= value
) {
802 log_err("unum_format result %d != value %d\n", parseResult
, value
);
808 log_err("Spellout format is unavailable\n");
811 { /* Test for ticket #7079 */
812 UNumberFormat
* dec_en
;
813 UChar groupingSep
[] = { 0 };
814 UChar numPercent
[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
815 double parseResult
= 0.0;
818 dec_en
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
819 unum_setAttribute(dec_en
, UNUM_LENIENT_PARSE
, 0);
820 unum_setSymbol(dec_en
, UNUM_GROUPING_SEPARATOR_SYMBOL
, groupingSep
, 0, &status
);
821 parseResult
= unum_parseDouble(dec_en
, numPercent
, -1, NULL
, &status
);
822 /* Without the fix in #7079, the above call will hang */
823 if ( U_FAILURE(status
) || parseResult
!= 12.0 ) {
824 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
825 myErrorName(status
), parseResult
);
827 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
832 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
833 to verify that it is taking the pure decimal path. */
835 const char *bdpattern
= "#,##0.#########";
836 const char *numInitial
= "12345678900987654321.1234567896";
837 const char *numFormatted
= "12,345,678,900,987,654,321.12345679";
838 const char *parseExpected
= "12345678900987654321.12345679";
839 int32_t resultSize
= 0;
840 int32_t parsePos
= 0; /* Output parameter for Parse operations. */
841 #define DESTCAPACITY 100
842 UChar dest
[DESTCAPACITY
];
843 char desta
[DESTCAPACITY
];
844 UFieldPosition fieldPos
= {0};
848 status
= U_ZERO_ERROR
;
849 u_uastrcpy(dest
, bdpattern
);
850 fmt
= unum_open(UNUM_PATTERN_DECIMAL
, dest
, -1, "en", NULL
/*parseError*/, &status
);
851 if (U_FAILURE(status
)) log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
853 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, NULL
, &status
);
854 if (U_FAILURE(status
)) {
855 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
857 u_austrncpy(desta
, dest
, DESTCAPACITY
);
858 if (strcmp(numFormatted
, desta
) != 0) {
859 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
860 __FILE__
, __LINE__
, numFormatted
, desta
);
862 if (strlen(numFormatted
) != resultSize
) {
863 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
864 __FILE__
, __LINE__
, strlen(numFormatted
), resultSize
);
867 /* Format with a FieldPosition parameter */
869 fieldPos
.field
= 2; /* Ticket 8034 - need enum constants for the field values. */
870 /* 2 = kDecimalSeparatorField */
871 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, &fieldPos
, &status
);
872 if (U_FAILURE(status
)) {
873 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
875 u_austrncpy(desta
, dest
, DESTCAPACITY
);
876 if (strcmp(numFormatted
, desta
) != 0) {
877 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
878 __FILE__
, __LINE__
, numFormatted
, desta
);
880 if (fieldPos
.beginIndex
!= 26) { /* index of "." in formatted number */
881 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
882 __FILE__
, __LINE__
, 0, fieldPos
.beginIndex
);
884 if (fieldPos
.endIndex
!= 27) {
885 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
886 __FILE__
, __LINE__
, 0, fieldPos
.endIndex
);
891 status
= U_ZERO_ERROR
;
892 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
893 resultSize
= unum_parseDecimal(fmt
, dest
, -1, NULL
, desta
, DESTCAPACITY
, &status
);
894 if (U_FAILURE(status
)) {
895 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
897 if (strcmp(parseExpected
, desta
) != 0) {
898 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
899 __FILE__
, __LINE__
, parseExpected
, desta
);
901 if (strlen(parseExpected
) != resultSize
) {
902 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
903 __FILE__
, __LINE__
, strlen(parseExpected
), resultSize
);
906 /* Parse with a parsePos parameter */
908 status
= U_ZERO_ERROR
;
909 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
910 parsePos
= 3; /* 12,345,678,900,987,654,321.12345679 */
911 /* start parsing at the the third char */
912 resultSize
= unum_parseDecimal(fmt
, dest
, -1, &parsePos
, desta
, DESTCAPACITY
, &status
);
913 if (U_FAILURE(status
)) {
914 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
916 if (strcmp(parseExpected
+2, desta
) != 0) { /* "345678900987654321.12345679" */
917 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
918 __FILE__
, __LINE__
, parseExpected
+2, desta
);
920 if (strlen(numFormatted
) != parsePos
) {
921 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
922 __FILE__
, __LINE__
, strlen(parseExpected
), parsePos
);
929 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
936 unum_close(spellout_def
);
938 unum_close(cur_frpattern
);
943 static void TestParseZero(void)
945 UErrorCode errorCode
= U_ZERO_ERROR
;
946 UChar input
[] = {'0', 0}; /* Input text is decimal '0' */
947 UChar pat
[] = {'#', ';', '#', 0};
951 UNumberFormat
* unum
= unum_open( UNUM_DECIMAL
/*or UNUM_DEFAULT*/, NULL
, -1, NULL
, NULL
, &errorCode
);
953 UNumberFormat
* unum
= unum_open( UNUM_PATTERN_DECIMAL
/*needs pattern*/, pat
, -1, NULL
, NULL
, &errorCode
);
956 dbl
= unum_parseDouble( unum
, input
, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode
);
957 if (U_FAILURE(errorCode
)) {
958 log_err("Result: %s\n", u_errorName(errorCode
));
960 log_verbose("Double: %f\n", dbl
);
965 const char * testname
;
968 const UChar
* source
;
975 static const UChar ustr_zh50d
[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
976 static const UChar ustr_zh05a
[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
977 static const UChar ustr_zh05d
[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
979 static const NumParseTestItem altnumParseTests
[] = {
980 /* name loc lenent src start val end status */
981 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
982 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
983 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
984 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
987 static void TestParseAltNum(void)
989 const NumParseTestItem
* testPtr
;
990 for (testPtr
= altnumParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
991 UErrorCode status
= U_ZERO_ERROR
;
992 int32_t value
, position
= testPtr
->startPos
;
993 UNumberFormat
*nf
= unum_open(UNUM_DECIMAL
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
994 if (U_FAILURE(status
)) {
995 log_err_status(status
, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
998 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
999 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1000 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1001 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1002 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1003 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1004 value
, position
, myErrorName(status
) );
1010 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1011 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1012 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1013 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1014 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1015 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1016 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent-vingt-trois */
1017 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1018 static const UChar ustr_zh50s
[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1019 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1020 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1021 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1023 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1025 static const NumParseTestItem spelloutParseTests
[] = {
1026 /* name loc lenent src start val end status */
1027 { "en0", "en", FALSE
, ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
1028 { "en0", "en", FALSE
, ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
1029 { "en0", "ja", FALSE
, ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
1030 #if NUMERIC_STRINGS_NOT_PARSEABLE
1031 { "123", "en", FALSE
, ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
1033 { "123", "en", FALSE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1035 { "123L", "en", TRUE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1036 { "en123", "en", FALSE
, ustr_en123
, 0, 123, 24, U_ZERO_ERROR
},
1037 { "en123", "en", FALSE
, ustr_en123
, 12, 23, 24, U_ZERO_ERROR
},
1038 { "en123", "fr", FALSE
, ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
1039 { "fr123", "fr", FALSE
, ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
1040 { "fr123", "fr", FALSE
, ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
1041 { "fr123", "en", FALSE
, ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
1042 { "ja123", "ja", FALSE
, ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
1043 { "ja123", "ja", FALSE
, ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
1044 { "ja123", "fr", FALSE
, ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
1045 { "zh,50s", "zh", FALSE
, ustr_zh50s
, 0, 50, 2, U_ZERO_ERROR
},
1046 #if NUMERIC_STRINGS_NOT_PARSEABLE
1047 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 5, 1, U_ZERO_ERROR
},
1048 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1049 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 0, 1, U_ZERO_ERROR
},
1051 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1052 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1053 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1055 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1056 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1057 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1058 { "zh,50dL","zh", TRUE
, ustr_zh50d
, 0, 5, 1, U_ZERO_ERROR
},
1059 { "zh,05aL","zh", TRUE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1060 { "zh,05dL","zh", TRUE
, ustr_zh05d
, 0, 0, 1, U_ZERO_ERROR
},
1061 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1064 static void TestSpelloutNumberParse()
1066 const NumParseTestItem
* testPtr
;
1067 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1068 UErrorCode status
= U_ZERO_ERROR
;
1069 int32_t value
, position
= testPtr
->startPos
;
1070 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1071 if (U_FAILURE(status
)) {
1072 log_err_status(status
, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1075 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1076 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1077 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1078 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1079 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1080 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1081 value
, position
, myErrorName(status
) );
1087 static void TestSignificantDigits()
1090 int32_t resultlengthneeded
;
1091 int32_t resultlength
;
1092 UErrorCode status
= U_ZERO_ERROR
;
1093 UChar
*result
= NULL
;
1095 double d
= 123456.789;
1097 u_uastrcpy(temp
, "###0.0#");
1098 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, NULL
, NULL
,&status
);
1099 if (U_FAILURE(status
)) {
1100 log_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1103 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1104 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
1106 u_uastrcpy(temp
, "123457");
1108 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
1109 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1111 status
=U_ZERO_ERROR
;
1112 resultlength
=resultlengthneeded
+1;
1113 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1114 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
1116 if(U_FAILURE(status
))
1118 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1121 if(u_strcmp(result
, temp
)==0)
1122 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1124 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1129 static void TestSigDigRounding()
1131 UErrorCode status
= U_ZERO_ERROR
;
1132 UChar expected
[128];
1139 fmt
=unum_open(UNUM_DECIMAL
, NULL
, 0, NULL
/* "en_US"*/, NULL
, &status
);
1140 if (U_FAILURE(status
)) {
1141 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1144 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, FALSE
);
1145 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1146 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2);
1147 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1149 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_UP
);
1150 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, 20.0);
1152 (void)unum_formatDouble(fmt
, d
, result
, sizeof(result
) / sizeof(result
[0]), NULL
, &status
);
1153 if(U_FAILURE(status
))
1155 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1159 u_uastrcpy(expected
, "140");
1160 if(u_strcmp(result
, expected
)!=0)
1161 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1
, result
), u_austrcpy(temp2
, expected
) );
1166 static void TestNumberFormatPadding()
1171 UErrorCode status
=U_ZERO_ERROR
;
1172 int32_t resultlength
;
1173 int32_t resultlengthneeded
;
1174 UNumberFormat
*pattern
;
1176 double d
= -10456.37;
1177 UFieldPosition pos1
;
1180 /* create a number format using unum_openPattern(....)*/
1181 log_verbose("\nTesting unum_openPattern() with padding\n");
1182 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
1183 status
=U_ZERO_ERROR
;
1184 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
1185 if(U_SUCCESS(status
))
1187 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );
1191 unum_close(pattern
);
1194 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1195 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
1196 status
=U_ZERO_ERROR
;
1197 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
1198 if(U_FAILURE(status
))
1200 log_err_status(status
, "error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
1203 log_verbose("Pass: padding unum_openPattern() works fine\n");
1205 /*test for unum_toPattern()*/
1206 log_verbose("\nTesting padding unum_toPattern()\n");
1208 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
1209 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1211 status
=U_ZERO_ERROR
;
1212 resultlength
=resultlengthneeded
+1;
1213 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1214 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
1216 if(U_FAILURE(status
))
1218 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
1222 if(u_strcmp(result
, temp1
)!=0)
1223 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
1225 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1228 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1229 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
1231 pos1
.field
= 1; /* Fraction field */
1232 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
1233 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1235 status
=U_ZERO_ERROR
;
1236 resultlength
=resultlengthneeded
+1;
1237 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1238 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
1240 if(U_FAILURE(status
))
1242 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
1246 if(u_strcmp(result
, temp1
)==0)
1247 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1249 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1250 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
1251 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1253 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1254 pos1
.beginIndex
, pos1
.endIndex
);
1257 /* Testing unum_parse() and unum_parseDouble() */
1258 log_verbose("\nTesting padding unum_parseDouble()\n");
1260 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
1261 if(U_FAILURE(status
))
1263 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
1267 log_err("Fail: Error in padding parsing\n");
1269 log_verbose("Pass: padding parsing successful\n");
1274 unum_close(pattern
);
1278 withinErr(double a
, double b
, double err
) {
1279 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
1282 static void TestInt64Format() {
1286 UErrorCode status
= U_ZERO_ERROR
;
1287 const double doubleInt64Max
= (double)U_INT64_MAX
;
1288 const double doubleInt64Min
= (double)U_INT64_MIN
;
1289 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
1295 /* create a number format using unum_openPattern(....) */
1296 log_verbose("\nTesting Int64Format\n");
1297 u_uastrcpy(temp1
, "#.#E0");
1298 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), NULL
, NULL
, &status
);
1299 if(U_FAILURE(status
)) {
1300 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
1302 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1303 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1304 if (U_FAILURE(status
)) {
1305 log_err("error in unum_format(): %s\n", myErrorName(status
));
1307 log_verbose("format int64max: '%s'\n", result
);
1309 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1310 if (status
!= U_INVALID_FORMAT_ERROR
) {
1311 log_err("parse didn't report error: %s\n", myErrorName(status
));
1312 } else if (val32
!= INT32_MAX
) {
1313 log_err("parse didn't pin return value, got: %d\n", val32
);
1316 status
= U_ZERO_ERROR
;
1318 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1319 if (U_FAILURE(status
)) {
1320 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1321 } else if (val64
!= U_INT64_MAX
) {
1322 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1325 status
= U_ZERO_ERROR
;
1327 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1328 if (U_FAILURE(status
)) {
1329 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1330 } else if (valDouble
!= doubleInt64Max
) {
1331 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1335 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1336 if (U_FAILURE(status
)) {
1337 log_err("error in unum_format(): %s\n", myErrorName(status
));
1339 log_verbose("format int64min: '%s'\n", result
);
1341 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1342 if (status
!= U_INVALID_FORMAT_ERROR
) {
1343 log_err("parse didn't report error: %s\n", myErrorName(status
));
1344 } else if (val32
!= INT32_MIN
) {
1345 log_err("parse didn't pin return value, got: %d\n", val32
);
1348 status
= U_ZERO_ERROR
;
1350 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1351 if (U_FAILURE(status
)) {
1352 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1353 } else if (val64
!= U_INT64_MIN
) {
1354 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1357 status
= U_ZERO_ERROR
;
1359 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1360 if (U_FAILURE(status
)) {
1361 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1362 } else if (valDouble
!= doubleInt64Min
) {
1363 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1367 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1368 if (U_FAILURE(status
)) {
1369 log_err("error in unum_format(): %s\n", myErrorName(status
));
1371 log_verbose("format doubleBig: '%s'\n", result
);
1373 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1374 if (status
!= U_INVALID_FORMAT_ERROR
) {
1375 log_err("parse didn't report error: %s\n", myErrorName(status
));
1376 } else if (val32
!= INT32_MAX
) {
1377 log_err("parse didn't pin return value, got: %d\n", val32
);
1380 status
= U_ZERO_ERROR
;
1382 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1383 if (status
!= U_INVALID_FORMAT_ERROR
) {
1384 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1385 } else if (val64
!= U_INT64_MAX
) {
1386 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1389 status
= U_ZERO_ERROR
;
1391 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1392 if (U_FAILURE(status
)) {
1393 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1394 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1395 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1399 unum_formatDouble(fmt
, 5.06e-27, result
, 512, NULL
, &status
);
1400 if (U_FAILURE(status
)) {
1401 log_err("error in unum_format(): %s\n", myErrorName(status
));
1403 log_verbose("format 5.06e-27: %s\n", result
);
1405 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1406 if (U_FAILURE(status
)) {
1407 log_err("parseDouble() returned error: %s\n", myErrorName(status
));
1408 } else if (!withinErr(valDouble
, 5.06e-27, 1e-15)) {
1409 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble
);
1417 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1420 int32_t BUFSIZE
= sizeof(buffer
)/sizeof(buffer
[0]);
1422 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1426 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1427 UErrorCode status
= U_ZERO_ERROR
;
1428 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1429 if (U_FAILURE(status
)) {
1430 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1432 u_austrcpy(temp
, buffer
);
1433 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1437 /* check APIs now */
1439 UErrorCode status
= U_ZERO_ERROR
;
1441 u_uastrcpy(buffer
, "#,##0.0#");
1442 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1443 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1444 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1449 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1450 log_verbose("lenient: 0x%x\n", isLenient
);
1451 if (isDecimal
? (isLenient
== TRUE
) : (isLenient
== TRUE
)) {
1452 log_err("didn't expect lenient value: %d\n", isLenient
);
1455 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1456 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1457 if (isDecimal
? (isLenient
== FALSE
) : (isLenient
== FALSE
)) {
1458 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1464 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1466 log_err("didn't expect double attribute\n");
1468 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1469 if ((val
== -1) == isDecimal
) {
1470 log_err("didn't expect -1 rounding increment\n");
1472 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1473 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1474 if (isDecimal
&& (val2
- val
!= .5)) {
1475 log_err("set rounding increment had no effect on decimal format");
1480 UErrorCode status
= U_ZERO_ERROR
;
1481 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1482 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1483 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1485 if (U_SUCCESS(status
)) {
1486 u_austrcpy(temp
, buffer
);
1487 log_verbose("default ruleset: '%s'\n", temp
);
1490 status
= U_ZERO_ERROR
;
1491 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1492 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1493 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1495 if (U_SUCCESS(status
)) {
1496 u_austrcpy(temp
, buffer
);
1497 log_verbose("public rulesets: '%s'\n", temp
);
1499 /* set the default ruleset to the first one found, and retry */
1502 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1505 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1506 if (U_FAILURE(status
)) {
1507 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1509 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1510 if (U_FAILURE(status
)) {
1511 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1512 } else if (len2
!= i
) {
1513 u_austrcpy(temp
, buffer
);
1514 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1516 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1517 status
= U_ZERO_ERROR
;
1518 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1519 if (U_FAILURE(status
)) {
1520 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1522 u_austrcpy(temp
, buffer
);
1523 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1534 UErrorCode status
= U_ZERO_ERROR
;
1535 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1536 if (U_SUCCESS(status
)) {
1537 u_austrcpy(temp
, buffer
);
1538 log_verbose("pattern: '%s'\n", temp
);
1539 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1540 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1542 log_verbose("pattern too long to display\n");
1547 UErrorCode status
= U_ZERO_ERROR
;
1548 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1549 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1550 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1553 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1554 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1555 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1560 static void TestNonExistentCurrency() {
1561 UNumberFormat
*format
;
1562 UErrorCode status
= U_ZERO_ERROR
;
1563 UChar currencySymbol
[8];
1564 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1566 /* Get a non-existent currency and make sure it returns the correct currency code. */
1567 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1568 if (format
== NULL
|| U_FAILURE(status
)) {
1569 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status
));
1572 unum_getSymbol(format
,
1573 UNUM_CURRENCY_SYMBOL
,
1575 sizeof(currencySymbol
)/sizeof(currencySymbol
[0]),
1577 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1578 log_err("unum_open set the currency to QQQ\n");
1584 static void TestRBNFFormat() {
1588 UChar tempUChars
[512];
1589 UNumberFormat
*formats
[5];
1590 int COUNT
= sizeof(formats
)/sizeof(formats
[0]);
1593 for (i
= 0; i
< COUNT
; ++i
) {
1598 status
= U_ZERO_ERROR
;
1599 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1600 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1601 if (U_FAILURE(status
)) {
1602 log_err_status(status
, "unable to open decimal pattern -> %s\n", u_errorName(status
));
1606 status
= U_ZERO_ERROR
;
1607 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1608 if (U_FAILURE(status
)) {
1609 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1613 status
= U_ZERO_ERROR
;
1614 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1615 if (U_FAILURE(status
)) {
1616 log_err_status(status
, "unable to open ordinal -> %s\n", u_errorName(status
));
1620 status
= U_ZERO_ERROR
;
1621 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1622 if (U_FAILURE(status
)) {
1623 log_err_status(status
, "unable to open duration %s\n", u_errorName(status
));
1627 status
= U_ZERO_ERROR
;
1631 "x.x: << point >>;\n"
1632 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1633 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1634 "seventeen; eighteen; nineteen;\n"
1635 "20: twenty[->>];\n"
1636 "30: thirty[->>];\n"
1640 "70: seventy[->>];\n"
1641 "80: eighty[->>];\n"
1642 "90: ninety[->>];\n"
1644 u_uastrcpy(tempUChars
,
1647 "20: twenty[ and change];\n"
1648 "30: thirty[ and change];\n"
1649 "40: forty[ and change];\n"
1650 "50: fifty[ and change];\n"
1651 "60: sixty[ and change];\n"
1652 "70: seventy[ and change];\n"
1653 "80: eighty[ and change];\n"
1654 "90: ninety[ and change];\n"
1658 "x.x: << point something;\n"
1660 "20: some reasonable number;\n"
1661 "100: some substantial number;\n"
1662 "100,000,000: some huge number;\n");
1663 /* This is to get around some compiler warnings about char * string length. */
1664 u_strcat(pat
, tempUChars
);
1665 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1666 if (U_FAILURE(status
)) {
1667 log_err_status(status
, "unable to open rulebased pattern -> %s\n", u_errorName(status
));
1669 if (U_FAILURE(status
)) {
1670 log_err_status(status
, "Something failed with %s\n", u_errorName(status
));
1674 for (i
= 0; i
< COUNT
; ++i
) {
1675 log_verbose("\n\ntesting format %d\n", i
);
1676 test_fmt(formats
[i
], (UBool
)(i
== 0));
1679 for (i
= 0; i
< COUNT
; ++i
) {
1680 unum_close(formats
[i
]);
1684 static void TestCurrencyRegression(void) {
1686 I've found a case where unum_parseDoubleCurrency is not doing what I
1687 expect. The value I pass in is $1234567890q123460000.00 and this
1688 returns with a status of zero error & a parse pos of 22 (I would
1689 expect a parse error at position 11).
1691 I stepped into DecimalFormat::subparse() and it looks like it parses
1692 the first 10 digits and then stops parsing at the q but doesn't set an
1693 error. Then later in DecimalFormat::parse() the value gets crammed
1694 into a long (which greatly truncates the value).
1696 This is very problematic for me 'cause I try to remove chars that are
1697 invalid but this allows my users to enter bad chars and truncates
1707 UErrorCode status
= U_ZERO_ERROR
;
1708 const int32_t expected
= 11;
1711 u_uastrcpy(buf
, "$1234567890q643210000.00");
1712 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1714 if(U_FAILURE(status
)) {
1715 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status
));
1719 status
= U_ZERO_ERROR
; /* so we can test it later. */
1722 d
= unum_parseDoubleCurrency(cur
,
1725 &pos
, /* 0 = start */
1729 u_austrcpy(acurrency
, currency
);
1731 if(U_FAILURE(status
) || (pos
!= expected
)) {
1732 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1733 expected
, d
, u_errorName(status
), pos
, acurrency
);
1735 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
1741 static void TestTextAttributeCrash(void) {
1742 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
1743 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1744 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1746 UErrorCode status
= U_ZERO_ERROR
;
1747 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
1748 if (U_FAILURE(status
)) {
1749 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status
));
1752 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
1754 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1755 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1757 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
1758 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
1759 if (U_FAILURE(status
)) {
1760 log_err("FAILED 2\n"); exit(1);
1762 log_verbose("attempting to format...\n");
1763 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
1764 if (U_FAILURE(status
) || 64 < used
) {
1765 log_err("Failed formatting %s\n", u_errorName(status
));
1768 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
1769 log_err("Didn't get expected negative result\n");
1771 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
1772 if (U_FAILURE(status
) || 64 < used
) {
1773 log_err("Failed formatting %s\n", u_errorName(status
));
1776 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
1777 log_err("Didn't get expected positive result\n");
1782 static void TestNBSPPatternRtNum(const char *testcase
, UNumberFormat
*nf
, double myNumber
) {
1783 UErrorCode status
= U_ZERO_ERROR
;
1786 double aNumber
= -1.0;
1787 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
1788 log_verbose("%s: formatted %.2f into %s\n", testcase
, myNumber
, u_austrcpy(tmpbuf
, myString
));
1789 if(U_FAILURE(status
)) {
1790 log_err("%s: failed format of %.2g with %s\n", testcase
, myNumber
, u_errorName(status
));
1793 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
1794 if(U_FAILURE(status
)) {
1795 log_err("%s: failed parse with %s\n", testcase
, u_errorName(status
));
1798 if(uprv_fabs(aNumber
-myNumber
)>.001) {
1799 log_err("FAIL: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1801 log_verbose("PASS: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1805 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
1806 TestNBSPPatternRtNum(testcase
, nf
, 12345.);
1807 TestNBSPPatternRtNum(testcase
, nf
, -12345.);
1810 static void TestNBSPInPattern(void) {
1811 UErrorCode status
= U_ZERO_ERROR
;
1812 UNumberFormat
* nf
= NULL
;
1813 const char *testcase
;
1816 testcase
="ar_AE UNUM_CURRENCY";
1817 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
1818 if(U_FAILURE(status
) || nf
== NULL
) {
1819 log_data_err("%s: unum_open failed with %s (Are you missing data?)\n", testcase
, u_errorName(status
));
1822 TestNBSPPatternRT(testcase
, nf
);
1824 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
1826 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
1828 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
1829 u_unescape(SPECIAL_PATTERN
, pat
, sizeof(pat
)/sizeof(pat
[0]));
1830 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
1831 if(U_FAILURE(status
)) {
1832 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
1834 TestNBSPPatternRT(testcase
, nf
);
1836 #undef SPECIAL_PATTERN
1838 unum_close(nf
); status
= U_ZERO_ERROR
;
1840 testcase
="ar_AE UNUM_DECIMAL";
1841 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
1842 if(U_FAILURE(status
)) {
1843 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1845 TestNBSPPatternRT(testcase
, nf
);
1846 unum_close(nf
); status
= U_ZERO_ERROR
;
1848 testcase
="ar_AE UNUM_PERCENT";
1849 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
1850 if(U_FAILURE(status
)) {
1851 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1853 TestNBSPPatternRT(testcase
, nf
);
1854 unum_close(nf
); status
= U_ZERO_ERROR
;
1860 #endif /* #if !UCONFIG_NO_FORMATTING */