1 /********************************************************************
3 * Copyright (c) 1997-2009, 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/unum.h"
28 #include "unicode/ustring.h"
34 #define LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
36 void addNumForTest(TestNode
** root
);
37 static void TestTextAttributeCrash(void);
38 static void TestNBSPInPattern(void);
40 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
42 void addNumForTest(TestNode
** root
)
44 TESTCASE(TestNumberFormat
);
45 TESTCASE(TestSpelloutNumberParse
);
46 TESTCASE(TestSignificantDigits
);
47 TESTCASE(TestNumberFormatPadding
);
48 TESTCASE(TestInt64Format
);
49 TESTCASE(TestNonExistentCurrency
);
50 TESTCASE(TestCurrencyRegression
);
51 TESTCASE(TestTextAttributeCrash
);
52 TESTCASE(TestRBNFFormat
);
53 TESTCASE(TestNBSPInPattern
);
56 /** copy src to dst with unicode-escapes for values < 0x20 and > 0x7e, null terminate if possible */
57 static int32_t ustrToAstr(const UChar
* src
, int32_t srcLength
, char* dst
, int32_t dstLength
) {
58 static const char hex
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
61 const char *e
= p
+ dstLength
;
67 srcLength
= (int32_t)(s
- src
);
69 while (p
< e
&& --srcLength
>= 0) {
71 if (c
== 0xd || c
== 0xa || c
== 0x9 || (c
>= 0x20 && c
<= 0x7e)) {
72 *p
++ = (char) c
& 0x7f;
73 } else if (e
- p
>= 6) {
76 *p
++ = hex
[(c
>> 12) & 0xf];
77 *p
++ = hex
[(c
>> 8) & 0xf];
78 *p
++ = hex
[(c
>> 4) & 0xf];
87 return (int32_t)(p
- dst
);
90 /* test Number Format API */
91 static void TestNumberFormat()
102 int32_t resultlength
;
103 int32_t resultlengthneeded
;
107 double d
= -10456.37;
108 double a
= 1234.56, a1
= 1235.0;
109 int32_t l
= 100000000;
115 UNumberFormatAttribute attr
;
116 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
118 UErrorCode status
=U_ZERO_ERROR
;
119 UNumberFormatStyle style
= UNUM_DEFAULT
;
120 UNumberFormat
*pattern
;
121 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
122 *cur_frpattern
, *myclone
, *spellout_def
;
124 /* Testing unum_open() with various Numberformat styles and locales*/
125 status
= U_ZERO_ERROR
;
126 log_verbose("Testing unum_open() with default style and locale\n");
127 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
129 /* Might as well pack it in now if we can't even get a default NumberFormat... */
130 if(U_FAILURE(status
))
132 log_err("Error in creating default NumberFormat using unum_open(): %s\n", myErrorName(status
));
136 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
137 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
138 if(U_FAILURE(status
))
139 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
141 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
143 /* Can't hardcode the result to assume the default locale is "en_US". */
144 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
145 if(U_FAILURE(status
))
146 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
147 myErrorName(status
) );
149 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
150 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
151 if(U_FAILURE(status
))
152 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
153 myErrorName(status
));
155 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
157 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
158 if(U_FAILURE(status
))
159 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
161 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
162 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
163 if(U_FAILURE(status
))
164 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
166 log_verbose("\nTesting unum_open(spellout, NULL, status)");
168 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
169 if(U_FAILURE(status
))
170 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
172 /* Testing unum_clone(..) */
173 log_verbose("\nTesting unum_clone(fmt, status)");
174 status
= U_ZERO_ERROR
;
175 myclone
= unum_clone(def
,&status
);
176 if(U_FAILURE(status
))
177 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
180 log_verbose("unum_clone() successful\n");
183 /*Testing unum_getAvailable() and unum_countAvailable()*/
184 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
185 numlocales
=unum_countAvailable();
187 log_err("error in countAvailable");
189 log_verbose("unum_countAvialable() successful\n");
190 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
192 for(i
=0;i
<numlocales
;i
++)
194 log_verbose("%s\n", unum_getAvailable(i
));
195 if (unum_getAvailable(i
) == 0)
196 log_err("No locale for which number formatting patterns are applicable\n");
198 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
202 /*Testing unum_format() and unum_formatdouble()*/
203 u_uastrcpy(temp1
, "$100,000,000.00");
205 log_verbose("\nTesting unum_format() \n");
207 pos1
.field
= 0; /* Integer Section */
208 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
209 if(status
==U_BUFFER_OVERFLOW_ERROR
)
212 resultlength
=resultlengthneeded
+1;
213 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
214 /* for (i = 0; i < 100000; i++) */
216 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
220 if(U_FAILURE(status
))
222 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
224 if(u_strcmp(result
, temp1
)==0)
225 log_verbose("Pass: Number formatting using unum_format() successful\n");
227 log_err("Fail: Error in number Formatting using unum_format()\n");
228 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
229 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
231 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
232 pos1
.beginIndex
, pos1
.endIndex
);
237 log_verbose("\nTesting unum_formatDouble()\n");
238 u_uastrcpy(temp1
, "($10,456.37)");
240 pos2
.field
= 1; /* Fractional Section */
241 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
242 if(status
==U_BUFFER_OVERFLOW_ERROR
)
245 resultlength
=resultlengthneeded
+1;
246 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
247 /* for (i = 0; i < 100000; i++) */
249 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
252 if(U_FAILURE(status
))
254 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
256 if(result
&& u_strcmp(result
, temp1
)==0)
257 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
259 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
260 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
261 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
263 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
264 pos1
.beginIndex
, pos1
.endIndex
);
267 /* Testing unum_parse() and unum_parseDouble() */
268 log_verbose("\nTesting unum_parseDouble()\n");
269 /* for (i = 0; i < 100000; i++)*/
273 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
276 log_err("result is NULL\n");
278 if(U_FAILURE(status
))
280 log_err("parse failed. The error is : %s\n", myErrorName(status
));
284 log_err("Fail: Error in parsing\n");
286 log_verbose("Pass: parsing successful\n");
292 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
293 log_verbose("\nTesting unum_formatDoubleCurrency\n");
294 u_uastrcpy(temp1
, "Y1,235");
295 temp1
[0] = 0xA5; /* Yen sign */
296 u_uastrcpy(temp
, "JPY");
298 pos2
.field
= 0; /* integer part */
299 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
300 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
302 resultlength
=resultlengthneeded
+1;
303 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
304 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
306 if (U_FAILURE(status
)) {
307 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
309 if (result
&& u_strcmp(result
, temp1
)==0) {
310 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
312 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
314 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
315 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
317 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
318 pos1
.beginIndex
, pos1
.endIndex
);
321 log_verbose("\nTesting unum_parseDoubleCurrency\n");
323 if (result
== NULL
) {
324 log_err("result is NULL\n");
327 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
328 if (U_FAILURE(status
)) {
329 log_err("parse failed. The error is : %s\n", myErrorName(status
));
331 /* Note: a==1234.56, but on parse expect a1=1235.0 */
333 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
335 log_verbose("Pass: parsed currency ammount successfully\n");
337 if (u_strcmp(temp2
, temp
)==0) {
338 log_verbose("Pass: parsed correct currency\n");
340 log_err("Fail: parsed incorrect currency\n");
348 /* performance testing */
349 u_uastrcpy(temp1
, "$462.12345");
350 resultlength
=u_strlen(temp1
);
351 /* for (i = 0; i < 100000; i++) */
354 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
356 if(U_FAILURE(status
))
358 log_err("parse failed. The error is : %s\n", myErrorName(status
));
362 log_err("Fail: Error in parsing\n");
364 log_verbose("Pass: parsing successful\n");
368 u_uastrcpy(temp1
, "($10,456.3E1])");
370 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
371 if(U_SUCCESS(status
))
373 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
377 log_verbose("\nTesting unum_format()\n");
381 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
382 if(status
==U_BUFFER_OVERFLOW_ERROR
)
385 resultlength
=resultlengthneeded
+1;
386 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
387 /* for (i = 0; i < 100000; i++)*/
389 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
392 if(U_FAILURE(status
))
394 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
398 log_verbose("\nTesting unum_parse()\n");
399 /* for (i = 0; i < 100000; i++) */
402 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
404 if(U_FAILURE(status
))
406 log_err("parse failed. The error is : %s\n", myErrorName(status
));
410 log_err("Fail: Error in parsing\n");
412 log_verbose("Pass: parsing successful\n");
416 /* create a number format using unum_openPattern(....)*/
417 log_verbose("\nTesting unum_openPattern()\n");
418 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
419 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
420 if(U_FAILURE(status
))
422 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
425 log_verbose("Pass: unum_openPattern() works fine\n");
427 /*test for unum_toPattern()*/
428 log_verbose("\nTesting unum_toPattern()\n");
430 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
431 if(status
==U_BUFFER_OVERFLOW_ERROR
)
434 resultlength
=resultlengthneeded
+1;
435 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
436 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
438 if(U_FAILURE(status
))
440 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
444 if(u_strcmp(result
, temp1
)!=0)
445 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
447 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
451 /*Testing unum_getSymbols() and unum_setSymbols()*/
452 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
453 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
455 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
456 if(status
==U_BUFFER_OVERFLOW_ERROR
)
459 resultlength
=resultlengthneeded
+1;
460 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
461 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
463 if(U_FAILURE(status
))
465 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
469 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
470 if(U_FAILURE(status
))
472 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
477 /*getting the symbols of cur_def */
478 /*set the symbols of cur_frpattern to cur_def */
479 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
481 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
482 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
483 if(U_FAILURE(status
))
485 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
489 /*format to check the result */
491 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
492 if(status
==U_BUFFER_OVERFLOW_ERROR
)
495 resultlength
=resultlengthneeded
+1;
496 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
497 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
499 if(U_FAILURE(status
))
501 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
504 if(U_FAILURE(status
)){
505 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
507 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
509 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
511 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
512 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
513 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
515 log_err("Fail: error in getting symbols\n");
518 log_verbose("Pass: get and set symbols successful\n");
521 /*format and check with the previous result */
524 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
525 if(status
==U_BUFFER_OVERFLOW_ERROR
)
528 resultlength
=resultlengthneeded
+1;
529 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
531 if(U_FAILURE(status
))
533 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
536 * This test fails because we have not called unum_applyPattern().
537 * Currently, such an applyPattern() does not exist on the C API, and
538 * we have jitterbug 411 for it.
539 * Since it is close to the 1.5 release, I (markus) am disabling this test just
540 * for this release (I added the test itself only last week).
541 * For the next release, we need to fix this.
542 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
544 if(u_strcmp(result
, temp1
) != 0) {
545 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
553 /* Testing unum_get/setSymbol() */
554 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
555 symbol
[0] = (UChar
)(0x41 + i
);
556 symbol
[1] = (UChar
)(0x61 + i
);
557 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
558 if(U_FAILURE(status
)) {
559 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
563 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
564 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
565 if(U_FAILURE(status
)) {
566 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
569 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
570 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
573 /*try getting from a bogus symbol*/
574 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
575 if(U_SUCCESS(status
)){
576 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
578 if(U_FAILURE(status
)){
579 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
580 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
585 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
586 log_verbose("\nTesting getting and setting text attributes\n");
588 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
589 if(U_FAILURE(status
))
591 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
593 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
594 if(U_FAILURE(status
))
596 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
598 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
599 if(U_FAILURE(status
))
601 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
603 if(u_strcmp(suffix
,temp
)!=0)
604 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
606 log_verbose("Pass: setting and getting suffix works fine\n");
607 /*set it back to normal */
608 u_uastrcpy(temp
,"$");
609 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
611 /*checking some more text setter conditions */
612 u_uastrcpy(prefix
, "+");
613 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
614 if(U_FAILURE(status
))
616 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
618 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
619 if(U_FAILURE(status
))
621 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
624 if(u_strcmp(prefix
, temp
)!=0)
625 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
627 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
629 u_uastrcpy(prefix
, "+");
630 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
631 if(U_FAILURE(status
))
633 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
635 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
636 if(U_FAILURE(status
))
638 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
640 if(u_strcmp(prefix
, temp
)!=0)
641 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
643 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
645 u_uastrcpy(suffix
, "+");
646 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
647 if(U_FAILURE(status
))
649 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
652 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
653 if(U_FAILURE(status
))
655 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
657 if(u_strcmp(suffix
, temp
)!=0)
658 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
660 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
662 u_uastrcpy(suffix
, "++");
663 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
664 if(U_FAILURE(status
))
666 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
669 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
670 if(U_FAILURE(status
))
672 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
674 if(u_strcmp(suffix
, temp
)!=0)
675 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
677 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
679 /*Testing unum_getAttribute and unum_setAttribute() */
680 log_verbose("\nTesting get and set Attributes\n");
681 attr
=UNUM_GROUPING_SIZE
;
682 newvalue
=unum_getAttribute(def
, attr
);
684 unum_setAttribute(def
, attr
, newvalue
);
685 if(unum_getAttribute(def
,attr
)!=2)
686 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
688 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
690 attr
=UNUM_MULTIPLIER
;
691 newvalue
=unum_getAttribute(def
, attr
);
693 unum_setAttribute(def
, attr
, newvalue
);
694 if(unum_getAttribute(def
,attr
) != 8)
695 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
697 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
699 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
700 newvalue
=unum_getAttribute(def
, attr
);
702 unum_setAttribute(def
, attr
, newvalue
);
703 if(unum_getAttribute(def
,attr
) != 2)
704 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
706 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
708 /*testing set and get Attributes extensively */
709 log_verbose("\nTesting get and set attributes extensively\n");
710 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
712 newvalue
=unum_getAttribute(fr
, attr
);
713 unum_setAttribute(def
, attr
, newvalue
);
714 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
715 log_err("error in setting and getting attributes\n");
717 log_verbose("Pass: attributes set and retrieved successfully\n");
720 /*testing spellout format to make sure we can use it successfully.*/
721 log_verbose("\nTesting spellout format\n");
724 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
725 for (i
= 0; i
< LENGTH(values
); ++i
) {
728 int32_t value
= values
[i
];
729 status
= U_ZERO_ERROR
;
730 len
= unum_format(spellout_def
, value
, buffer
, LENGTH(buffer
), NULL
, &status
);
731 if(U_FAILURE(status
)) {
732 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
737 ustrToAstr(buffer
, len
, logbuf
, LENGTH(logbuf
));
738 log_verbose("formatted %d as '%s', length: %d\n", value
, logbuf
, len
);
740 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
741 if (U_FAILURE(status
)) {
742 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
743 } else if (parseResult
!= value
) {
744 log_err("unum_format result %d != value %d\n", parseResult
, value
);
750 log_err("Spellout format is unavailable\n");
753 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
760 unum_close(spellout_def
);
762 unum_close(cur_frpattern
);
768 const char * testname
;
770 const UChar
* source
;
777 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
778 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
779 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
780 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
781 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred and twenty-three */
782 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
783 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
784 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
786 static const SpelloutParseTest spelloutParseTests
[] = {
787 /* name loc src start val end status */
788 { "en0", "en", ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
789 { "en0", "en", ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
790 { "en0", "ja", ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
791 { "123", "en", ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
792 { "en123", "en", ustr_en123
, 0, 123, 28, U_ZERO_ERROR
},
793 { "en123", "en", ustr_en123
, 16, 23, 28, U_ZERO_ERROR
},
794 { "en123", "fr", ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
795 { "fr123", "fr", ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
796 { "fr123", "fr", ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
797 { "fr123", "en", ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
798 { "ja123", "ja", ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
799 { "ja123", "ja", ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
800 { "ja123", "fr", ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
801 { NULL
, NULL
, NULL
, 0, 0, 0, 0 } /* terminator */
804 static void TestSpelloutNumberParse()
806 const SpelloutParseTest
* testPtr
;
807 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
808 UErrorCode status
= U_ZERO_ERROR
;
809 int32_t value
, position
= testPtr
->startPos
;
810 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
811 if (U_FAILURE(status
)) {
812 log_err("unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
815 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
816 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
817 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
818 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
819 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
820 value
, position
, myErrorName(status
) );
826 static void TestSignificantDigits()
829 int32_t resultlengthneeded
;
830 int32_t resultlength
;
831 UErrorCode status
= U_ZERO_ERROR
;
832 UChar
*result
= NULL
;
834 double d
= 123456.789;
836 u_uastrcpy(temp
, "###0.0#");
837 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, NULL
, NULL
,&status
);
838 if (U_FAILURE(status
)) {
839 log_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
842 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
843 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
845 u_uastrcpy(temp
, "123457");
847 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
848 if(status
==U_BUFFER_OVERFLOW_ERROR
)
851 resultlength
=resultlengthneeded
+1;
852 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
853 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
855 if(U_FAILURE(status
))
857 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
860 if(u_strcmp(result
, temp
)==0)
861 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
863 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
868 static void TestNumberFormatPadding()
873 UErrorCode status
=U_ZERO_ERROR
;
874 int32_t resultlength
;
875 int32_t resultlengthneeded
;
876 UNumberFormat
*pattern
;
878 double d
= -10456.37;
882 /* create a number format using unum_openPattern(....)*/
883 log_verbose("\nTesting unum_openPattern() with padding\n");
884 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
886 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
887 if(U_SUCCESS(status
))
889 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
896 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
897 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
899 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
900 if(U_FAILURE(status
))
902 log_err("error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
905 log_verbose("Pass: padding unum_openPattern() works fine\n");
907 /*test for unum_toPattern()*/
908 log_verbose("\nTesting padding unum_toPattern()\n");
910 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
911 if(status
==U_BUFFER_OVERFLOW_ERROR
)
914 resultlength
=resultlengthneeded
+1;
915 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
916 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
918 if(U_FAILURE(status
))
920 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
924 if(u_strcmp(result
, temp1
)!=0)
925 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
927 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
930 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
931 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
933 pos1
.field
= 1; /* Fraction field */
934 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
935 if(status
==U_BUFFER_OVERFLOW_ERROR
)
938 resultlength
=resultlengthneeded
+1;
939 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
940 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
942 if(U_FAILURE(status
))
944 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
948 if(u_strcmp(result
, temp1
)==0)
949 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
951 log_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
952 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
953 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
955 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
956 pos1
.beginIndex
, pos1
.endIndex
);
959 /* Testing unum_parse() and unum_parseDouble() */
960 log_verbose("\nTesting padding unum_parseDouble()\n");
962 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
963 if(U_FAILURE(status
))
965 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
969 log_err("Fail: Error in padding parsing\n");
971 log_verbose("Pass: padding parsing successful\n");
980 withinErr(double a
, double b
, double err
) {
981 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
984 static void TestInt64Format() {
988 UErrorCode status
= U_ZERO_ERROR
;
989 const double doubleInt64Max
= (double)U_INT64_MAX
;
990 const double doubleInt64Min
= (double)U_INT64_MIN
;
991 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
997 /* create a number format using unum_openPattern(....) */
998 log_verbose("\nTesting Int64Format\n");
999 u_uastrcpy(temp1
, "#.#E0");
1000 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), NULL
, NULL
, &status
);
1001 if(U_FAILURE(status
)) {
1002 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
1004 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1005 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1006 if (U_FAILURE(status
)) {
1007 log_err("error in unum_format(): %s\n", myErrorName(status
));
1009 log_verbose("format int64max: '%s'\n", result
);
1011 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1012 if (status
!= U_INVALID_FORMAT_ERROR
) {
1013 log_err("parse didn't report error: %s\n", myErrorName(status
));
1014 } else if (val32
!= INT32_MAX
) {
1015 log_err("parse didn't pin return value, got: %d\n", val32
);
1018 status
= U_ZERO_ERROR
;
1020 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1021 if (U_FAILURE(status
)) {
1022 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1023 } else if (val64
!= U_INT64_MAX
) {
1024 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1027 status
= U_ZERO_ERROR
;
1029 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1030 if (U_FAILURE(status
)) {
1031 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1032 } else if (valDouble
!= doubleInt64Max
) {
1033 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1037 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1038 if (U_FAILURE(status
)) {
1039 log_err("error in unum_format(): %s\n", myErrorName(status
));
1041 log_verbose("format int64min: '%s'\n", result
);
1043 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1044 if (status
!= U_INVALID_FORMAT_ERROR
) {
1045 log_err("parse didn't report error: %s\n", myErrorName(status
));
1046 } else if (val32
!= INT32_MIN
) {
1047 log_err("parse didn't pin return value, got: %d\n", val32
);
1050 status
= U_ZERO_ERROR
;
1052 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1053 if (U_FAILURE(status
)) {
1054 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1055 } else if (val64
!= U_INT64_MIN
) {
1056 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1059 status
= U_ZERO_ERROR
;
1061 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1062 if (U_FAILURE(status
)) {
1063 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1064 } else if (valDouble
!= doubleInt64Min
) {
1065 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1069 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1070 if (U_FAILURE(status
)) {
1071 log_err("error in unum_format(): %s\n", myErrorName(status
));
1073 log_verbose("format doubleBig: '%s'\n", result
);
1075 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1076 if (status
!= U_INVALID_FORMAT_ERROR
) {
1077 log_err("parse didn't report error: %s\n", myErrorName(status
));
1078 } else if (val32
!= INT32_MAX
) {
1079 log_err("parse didn't pin return value, got: %d\n", val32
);
1082 status
= U_ZERO_ERROR
;
1084 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1085 if (status
!= U_INVALID_FORMAT_ERROR
) {
1086 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1087 } else if (val64
!= U_INT64_MAX
) {
1088 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1091 status
= U_ZERO_ERROR
;
1093 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1094 if (U_FAILURE(status
)) {
1095 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1096 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1097 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1105 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1108 int32_t BUFSIZE
= sizeof(buffer
)/sizeof(buffer
[0]);
1110 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1114 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1115 UErrorCode status
= U_ZERO_ERROR
;
1116 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1117 if (U_FAILURE(status
)) {
1118 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1120 u_austrcpy(temp
, buffer
);
1121 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1125 /* check APIs now */
1127 UErrorCode status
= U_ZERO_ERROR
;
1129 u_uastrcpy(buffer
, "#,##0.0#");
1130 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1131 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1132 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1137 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1138 log_verbose("lenient: 0x%x\n", isLenient
);
1139 if (isDecimal
? (isLenient
== TRUE
) : (isLenient
== TRUE
)) {
1140 log_err("didn't expect lenient value: %d\n", isLenient
);
1143 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1144 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1145 if (isDecimal
? (isLenient
== FALSE
) : (isLenient
== FALSE
)) {
1146 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1152 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1154 log_err("didn't expect double attribute\n");
1156 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1157 if ((val
== -1) == isDecimal
) {
1158 log_err("didn't expect -1 rounding increment\n");
1160 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1161 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1162 if (isDecimal
&& (val2
- val
!= .5)) {
1163 log_err("set rounding increment had no effect on decimal format");
1168 UErrorCode status
= U_ZERO_ERROR
;
1169 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1170 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1171 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1173 if (U_SUCCESS(status
)) {
1174 u_austrcpy(temp
, buffer
);
1175 log_verbose("default ruleset: '%s'\n", temp
);
1178 status
= U_ZERO_ERROR
;
1179 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1180 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1181 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1183 if (U_SUCCESS(status
)) {
1184 u_austrcpy(temp
, buffer
);
1185 log_verbose("public rulesets: '%s'\n", temp
);
1187 /* set the default ruleset to the first one found, and retry */
1190 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1193 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1194 if (U_FAILURE(status
)) {
1195 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1197 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1198 if (U_FAILURE(status
)) {
1199 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1200 } else if (len2
!= i
) {
1201 u_austrcpy(temp
, buffer
);
1202 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1204 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1205 status
= U_ZERO_ERROR
;
1206 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1207 if (U_FAILURE(status
)) {
1208 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1210 u_austrcpy(temp
, buffer
);
1211 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1222 UErrorCode status
= U_ZERO_ERROR
;
1223 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1224 if (U_SUCCESS(status
)) {
1225 u_austrcpy(temp
, buffer
);
1226 log_verbose("pattern: '%s'\n", temp
);
1227 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1228 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1230 log_verbose("pattern too long to display\n");
1235 UErrorCode status
= U_ZERO_ERROR
;
1236 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1237 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1238 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1241 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1242 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1243 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1248 static void TestNonExistentCurrency() {
1249 UNumberFormat
*format
;
1250 UErrorCode status
= U_ZERO_ERROR
;
1251 UChar currencySymbol
[8];
1252 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1254 /* Get a non-existent currency and make sure it returns the correct currency code. */
1255 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1256 if (format
== NULL
|| U_FAILURE(status
)) {
1257 log_err("unum_open did not return expected result for non-existent requested currency: '%s'\n", u_errorName(status
));
1260 unum_getSymbol(format
,
1261 UNUM_CURRENCY_SYMBOL
,
1263 sizeof(currencySymbol
)/sizeof(currencySymbol
[0]),
1265 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1266 log_err("unum_open set the currency to QQQ\n");
1272 static void TestRBNFFormat() {
1276 UChar tempUChars
[512];
1277 UNumberFormat
*formats
[5];
1278 int COUNT
= sizeof(formats
)/sizeof(formats
[0]);
1281 for (i
= 0; i
< COUNT
; ++i
) {
1286 status
= U_ZERO_ERROR
;
1287 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1288 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1289 if (U_FAILURE(status
)) {
1290 log_err("unable to open decimal pattern\n");
1293 status
= U_ZERO_ERROR
;
1294 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1295 if (U_FAILURE(status
)) {
1296 log_err("unable to open spellout\n");
1299 status
= U_ZERO_ERROR
;
1300 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1301 if (U_FAILURE(status
)) {
1302 log_err("unable to open ordinal\n");
1305 status
= U_ZERO_ERROR
;
1306 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1307 if (U_FAILURE(status
)) {
1308 log_err("unable to open duration\n");
1311 status
= U_ZERO_ERROR
;
1315 "x.x: << point >>;\n"
1316 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1317 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1318 "seventeen; eighteen; nineteen;\n"
1319 "20: twenty[->>];\n"
1320 "30: thirty[->>];\n"
1324 "70: seventy[->>];\n"
1325 "80: eighty[->>];\n"
1326 "90: ninety[->>];\n"
1328 u_uastrcpy(tempUChars
,
1331 "20: twenty[ and change];\n"
1332 "30: thirty[ and change];\n"
1333 "40: forty[ and change];\n"
1334 "50: fifty[ and change];\n"
1335 "60: sixty[ and change];\n"
1336 "70: seventy[ and change];\n"
1337 "80: eighty[ and change];\n"
1338 "90: ninety[ and change];\n"
1342 "x.x: << point something;\n"
1344 "20: some reasonable number;\n"
1345 "100: some substantial number;\n"
1346 "100,000,000: some huge number;\n");
1347 /* This is to get around some compiler warnings about char * string length. */
1348 u_strcat(pat
, tempUChars
);
1349 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1350 if (U_FAILURE(status
)) {
1351 log_err("unable to open rulebased pattern\n");
1353 if (U_FAILURE(status
)) {
1354 log_err("Something failed with %s\n", u_errorName(status
));
1358 for (i
= 0; i
< COUNT
; ++i
) {
1359 log_verbose("\n\ntesting format %d\n", i
);
1360 test_fmt(formats
[i
], (UBool
)(i
== 0));
1363 for (i
= 0; i
< COUNT
; ++i
) {
1364 unum_close(formats
[i
]);
1368 static void TestCurrencyRegression(void) {
1370 I've found a case where unum_parseDoubleCurrency is not doing what I
1371 expect. The value I pass in is $1234567890q123460000.00 and this
1372 returns with a status of zero error & a parse pos of 22 (I would
1373 expect a parse error at position 11).
1375 I stepped into DecimalFormat::subparse() and it looks like it parses
1376 the first 10 digits and then stops parsing at the q but doesn't set an
1377 error. Then later in DecimalFormat::parse() the value gets crammed
1378 into a long (which greatly truncates the value).
1380 This is very problematic for me 'cause I try to remove chars that are
1381 invalid but this allows my users to enter bad chars and truncates
1391 UErrorCode status
= U_ZERO_ERROR
;
1392 const int32_t expected
= 11;
1395 u_uastrcpy(buf
, "$1234567890q643210000.00");
1396 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1398 if(U_FAILURE(status
)) {
1399 log_err("unum_open failed: %s\n", u_errorName(status
));
1403 status
= U_ZERO_ERROR
; /* so we can test it later. */
1406 d
= unum_parseDoubleCurrency(cur
,
1409 &pos
, /* 0 = start */
1413 u_austrcpy(acurrency
, currency
);
1415 if(U_FAILURE(status
) || (pos
!= expected
)) {
1416 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1417 expected
, d
, u_errorName(status
), pos
, acurrency
);
1419 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
1425 static void TestTextAttributeCrash(void) {
1426 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
1427 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1428 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1430 UErrorCode status
= U_ZERO_ERROR
;
1431 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
1432 if (U_FAILURE(status
)) {
1433 log_err("FAILED 1\n");
1436 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
1438 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1439 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1441 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
1442 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
1443 if (U_FAILURE(status
)) {
1444 log_err("FAILED 2\n"); exit(1);
1446 log_verbose("attempting to format...\n");
1447 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
1448 if (U_FAILURE(status
) || 64 < used
) {
1449 log_err("Failed formatting %s\n", u_errorName(status
));
1452 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
1453 log_err("Didn't get expected negative result\n");
1455 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
1456 if (U_FAILURE(status
) || 64 < used
) {
1457 log_err("Failed formatting %s\n", u_errorName(status
));
1460 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
1461 log_err("Didn't get expected positive result\n");
1466 static void TestNBSPPatternRtNum(const char *testcase
, UNumberFormat
*nf
, double myNumber
) {
1467 UErrorCode status
= U_ZERO_ERROR
;
1470 double aNumber
= -1.0;
1471 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
1472 log_verbose("%s: formatted %.2f into %s\n", testcase
, myNumber
, u_austrcpy(tmpbuf
, myString
));
1473 if(U_FAILURE(status
)) {
1474 log_err("%s: failed format of %.2g with %s\n", testcase
, myNumber
, u_errorName(status
));
1477 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
1478 if(U_FAILURE(status
)) {
1479 log_err("%s: failed parse with %s\n", testcase
, u_errorName(status
));
1482 if(uprv_fabs(aNumber
-myNumber
)>.001) {
1483 log_err("FAIL: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1485 log_verbose("PASS: %s: formatted %.2f, parsed into %.2f\n", testcase
, myNumber
, aNumber
);
1489 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
1490 TestNBSPPatternRtNum(testcase
, nf
, 12345.);
1491 TestNBSPPatternRtNum(testcase
, nf
, -12345.);
1494 static void TestNBSPInPattern(void) {
1495 UErrorCode status
= U_ZERO_ERROR
;
1496 UNumberFormat
* nf
= NULL
;
1497 const char *testcase
;
1500 testcase
="ar_AE UNUM_CURRENCY";
1501 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
1502 if(U_FAILURE(status
)) {
1503 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1505 TestNBSPPatternRT(testcase
, nf
);
1507 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
1509 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
1511 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
1512 u_unescape(SPECIAL_PATTERN
, pat
, sizeof(pat
)/sizeof(pat
[0]));
1513 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
1514 if(U_FAILURE(status
)) {
1515 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
1517 TestNBSPPatternRT(testcase
, nf
);
1519 #undef SPECIAL_PATTERN
1521 unum_close(nf
); status
= U_ZERO_ERROR
;
1523 testcase
="ar_AE UNUM_DECIMAL";
1524 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
1525 if(U_FAILURE(status
)) {
1526 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1528 TestNBSPPatternRT(testcase
, nf
);
1529 unum_close(nf
); status
= U_ZERO_ERROR
;
1531 testcase
="ar_AE UNUM_PERCENT";
1532 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
1533 if(U_FAILURE(status
)) {
1534 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1536 TestNBSPPatternRT(testcase
, nf
);
1537 unum_close(nf
); status
= U_ZERO_ERROR
;
1543 #endif /* #if !UCONFIG_NO_FORMATTING */