1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8 /********************************************************************************
12 * Madhu Katragadda Creation
14 * Modification History:
16 * Date Name Description
17 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
18 * 07/15/99 helena Ported to HPUX 10/11 CC.
19 *********************************************************************************
22 /* C API TEST FOR NUMBER FORMAT */
24 #include "unicode/utypes.h"
26 #if !UCONFIG_NO_FORMATTING
28 #include "unicode/uloc.h"
29 #include "unicode/umisc.h"
30 #include "unicode/unum.h"
31 #include "unicode/unumsys.h"
32 #include "unicode/ustring.h"
33 #include "unicode/udisplaycontext.h"
43 static const char *tagAssert(const char *f
, int32_t l
, const char *msg
) {
44 static char _fileline
[1000];
45 sprintf(_fileline
, "%s:%d: ASSERT_TRUE(%s)", f
, l
, msg
);
49 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
51 void addNumForTest(TestNode
** root
);
52 static void TestTextAttributeCrash(void);
53 static void TestNBSPInPattern(void);
54 static void TestInt64Parse(void);
55 static void TestParseCurrency(void);
56 static void TestMaxInt(void);
57 static void TestNoExponent(void);
58 static void TestUFormattable(void);
59 static void TestUNumberingSystem(void);
60 static void TestCurrencyIsoPluralFormat(void);
61 static void TestContext(void);
62 static void TestCurrencyUsage(void);
63 static void TestCurrFmtNegSameAsPositive(void);
64 static void TestVariousStylesAndAttributes(void);
65 static void TestParseCurrPatternWithDecStyle(void);
66 static void TestFormatForFields(void);
67 static void TestRBNFRounding(void);
68 static void Test12052_NullPointer(void);
69 static void TestParseAltNum(void);
70 static void TestParseCurrPatternWithDecStyle(void);
71 static void TestParseCases(void);
72 static void TestFormatPrecision(void);
73 static void TestSciNotationRound(void); // Apple <rdar://problem/49159521>
75 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
77 void addNumForTest(TestNode
** root
)
79 TESTCASE(TestNumberFormat
);
80 TESTCASE(TestSpelloutNumberParse
);
81 TESTCASE(TestSignificantDigits
);
82 TESTCASE(TestSigDigRounding
);
83 TESTCASE(TestNumberFormatPadding
);
84 TESTCASE(TestInt64Format
);
85 TESTCASE(TestNonExistentCurrency
);
86 TESTCASE(TestCurrencyRegression
);
87 TESTCASE(TestTextAttributeCrash
);
88 TESTCASE(TestRBNFFormat
);
89 TESTCASE(TestRBNFRounding
);
90 TESTCASE(TestNBSPInPattern
);
91 TESTCASE(TestInt64Parse
);
92 TESTCASE(TestParseZero
);
93 TESTCASE(TestParseCurrency
);
94 TESTCASE(TestCloneWithRBNF
);
96 TESTCASE(TestNoExponent
);
97 TESTCASE(TestUFormattable
);
98 TESTCASE(TestUNumberingSystem
);
99 TESTCASE(TestCurrencyIsoPluralFormat
);
100 TESTCASE(TestContext
);
101 TESTCASE(TestCurrencyUsage
);
102 TESTCASE(TestCurrFmtNegSameAsPositive
);
103 TESTCASE(TestVariousStylesAndAttributes
);
104 TESTCASE(TestParseCurrPatternWithDecStyle
);
105 TESTCASE(TestFormatForFields
);
106 //TESTCASE(Test12052_NullPointer);
107 TESTCASE(TestParseAltNum
);
108 TESTCASE(TestParseCurrPatternWithDecStyle
);
109 TESTCASE(TestParseCases
);
110 TESTCASE(TestFormatPrecision
);
111 TESTCASE(TestSciNotationRound
);
114 /* test Parse int 64 */
116 static void TestInt64Parse()
119 UErrorCode st
= U_ZERO_ERROR
;
120 UErrorCode
* status
= &st
;
122 const char* st1
= "009223372036854775808";
131 u_charsToUChars(st1
, text
, size
);
132 nf
= unum_open(UNUM_DEFAULT
, NULL
, -1, NULL
, NULL
, status
);
134 if(U_FAILURE(*status
))
136 log_data_err("Error in unum_open() %s \n", myErrorName(*status
));
140 log_verbose("About to test unum_parseInt64() with out of range number\n");
142 a
= unum_parseInt64(nf
, text
, size
, 0, status
);
143 (void)a
; /* Suppress set but not used warning. */
146 if(!U_FAILURE(*status
))
148 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status
));
152 log_verbose("unum_parseInt64() successful\n");
159 /* test Number Format API */
160 static void TestNumberFormat()
171 int32_t resultlength
;
172 int32_t resultlengthneeded
;
176 double d
= -10456.37;
177 double a
= 1234.56, a1
= 1235.0;
178 int32_t l
= 100000000;
184 UNumberFormatAttribute attr
;
185 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
187 UErrorCode status
=U_ZERO_ERROR
;
188 UNumberFormatStyle style
= UNUM_DEFAULT
;
189 UNumberFormat
*pattern
;
190 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
191 *cur_frpattern
, *myclone
, *spellout_def
;
193 /* Testing unum_open() with various Numberformat styles and locales*/
194 status
= U_ZERO_ERROR
;
195 log_verbose("Testing unum_open() with default style and locale\n");
196 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
198 /* Might as well pack it in now if we can't even get a default NumberFormat... */
199 if(U_FAILURE(status
))
201 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status
));
205 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
206 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
207 if(U_FAILURE(status
))
208 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
210 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
212 /* Can't hardcode the result to assume the default locale is "en_US". */
213 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
214 if(U_FAILURE(status
))
215 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
216 myErrorName(status
) );
218 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
219 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
220 if(U_FAILURE(status
))
221 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
222 myErrorName(status
));
224 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
226 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
227 if(U_FAILURE(status
))
228 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
230 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
231 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
232 if(U_FAILURE(status
))
233 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
235 log_verbose("\nTesting unum_open(spellout, NULL, status)");
237 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
238 if(U_FAILURE(status
))
239 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
241 /* Testing unum_clone(..) */
242 log_verbose("\nTesting unum_clone(fmt, status)");
243 status
= U_ZERO_ERROR
;
244 myclone
= unum_clone(def
,&status
);
245 if(U_FAILURE(status
))
246 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
249 log_verbose("unum_clone() successful\n");
252 /*Testing unum_getAvailable() and unum_countAvailable()*/
253 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
254 numlocales
=unum_countAvailable();
256 log_err("error in countAvailable");
258 log_verbose("unum_countAvialable() successful\n");
259 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
261 for(i
=0;i
<numlocales
;i
++)
263 log_verbose("%s\n", unum_getAvailable(i
));
264 if (unum_getAvailable(i
) == 0)
265 log_err("No locale for which number formatting patterns are applicable\n");
267 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
271 /*Testing unum_format() and unum_formatdouble()*/
272 u_uastrcpy(temp1
, "$100,000,000.00");
274 log_verbose("\nTesting unum_format() \n");
276 pos1
.field
= UNUM_INTEGER_FIELD
;
277 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
278 if(status
==U_BUFFER_OVERFLOW_ERROR
)
281 resultlength
=resultlengthneeded
+1;
282 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
283 /* for (i = 0; i < 100000; i++) */
285 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
289 if(U_FAILURE(status
))
291 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
293 if(u_strcmp(result
, temp1
)==0)
294 log_verbose("Pass: Number formatting using unum_format() successful\n");
296 log_err("Fail: Error in number Formatting using unum_format()\n");
297 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
298 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
300 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
301 pos1
.beginIndex
, pos1
.endIndex
);
306 log_verbose("\nTesting unum_formatDouble()\n");
307 u_uastrcpy(temp1
, "-$10,456.37");
309 pos2
.field
= UNUM_FRACTION_FIELD
;
310 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
311 if(status
==U_BUFFER_OVERFLOW_ERROR
)
314 resultlength
=resultlengthneeded
+1;
315 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
316 /* for (i = 0; i < 100000; i++) */
318 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
321 if(U_FAILURE(status
))
323 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
325 if(result
&& u_strcmp(result
, temp1
)==0)
326 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
328 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
329 aescstrdup(result
, -1), aescstrdup(temp1
, -1));
331 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
332 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
334 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
335 pos1
.beginIndex
, pos1
.endIndex
);
338 /* Testing unum_parse() and unum_parseDouble() */
339 log_verbose("\nTesting unum_parseDouble()\n");
340 /* for (i = 0; i < 100000; i++)*/
342 if (result
!= NULL
) {
343 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
345 log_err("result is NULL\n");
347 if(U_FAILURE(status
)) {
348 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result
,u_strlen(result
)),parsepos
, myErrorName(status
));
352 log_err("Fail: Error in parsing\n");
354 log_verbose("Pass: parsing successful\n");
359 status
= U_ZERO_ERROR
;
360 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
361 log_verbose("\nTesting unum_formatDoubleCurrency\n");
362 u_uastrcpy(temp1
, "Y1,235");
363 temp1
[0] = 0xA5; /* Yen sign */
364 u_uastrcpy(temp
, "JPY");
366 pos2
.field
= UNUM_INTEGER_FIELD
;
367 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
368 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
370 resultlength
=resultlengthneeded
+1;
371 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
372 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
374 if (U_FAILURE(status
)) {
375 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status
));
377 if (result
&& u_strcmp(result
, temp1
)==0) {
378 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
380 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
381 aescstrdup(result
, -1), aescstrdup(temp1
, -1));
383 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
384 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
386 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
387 pos1
.beginIndex
, pos1
.endIndex
);
390 log_verbose("\nTesting unum_parseDoubleCurrency\n");
392 if (result
== NULL
) {
393 log_err("result is NULL\n");
396 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
397 if (U_FAILURE(status
)) {
398 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result
, u_strlen(result
)), myErrorName(status
));
400 /* Note: a==1234.56, but on parse expect a1=1235.0 */
402 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
404 log_verbose("Pass: parsed currency amount successfully\n");
406 if (u_strcmp(temp2
, temp
)==0) {
407 log_verbose("Pass: parsed correct currency\n");
409 log_err("Fail: parsed incorrect currency\n");
412 status
= U_ZERO_ERROR
; /* reset */
418 /* performance testing */
419 u_uastrcpy(temp1
, "$462.12345");
420 resultlength
=u_strlen(temp1
);
421 /* for (i = 0; i < 100000; i++) */
424 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
426 if(U_FAILURE(status
))
428 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1
, resultlength
), myErrorName(status
));
432 * Note: "for strict standard conformance all operations and constants are now supposed to be
433 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
438 log_err("Fail: Error in parsing\n");
440 log_verbose("Pass: parsing successful\n");
444 u_uastrcpy(temp1
, "($10,456.3E1])");
446 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
447 if(U_SUCCESS(status
))
449 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
453 log_verbose("\nTesting unum_format()\n");
457 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
458 if(status
==U_BUFFER_OVERFLOW_ERROR
)
461 resultlength
=resultlengthneeded
+1;
462 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
463 /* for (i = 0; i < 100000; i++)*/
465 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
468 if(U_FAILURE(status
))
470 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
474 log_verbose("\nTesting unum_parse()\n");
475 /* for (i = 0; i < 100000; i++) */
478 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
480 if(U_FAILURE(status
))
482 log_err("parse failed. The error is : %s\n", myErrorName(status
));
486 log_err("Fail: Error in parsing\n");
488 log_verbose("Pass: parsing successful\n");
492 /* create a number format using unum_openPattern(....)*/
493 log_verbose("\nTesting unum_openPattern()\n");
494 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
495 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
496 if(U_FAILURE(status
))
498 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
501 log_verbose("Pass: unum_openPattern() works fine\n");
503 /*test for unum_toPattern()*/
504 log_verbose("\nTesting unum_toPattern()\n");
506 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
507 if(status
==U_BUFFER_OVERFLOW_ERROR
)
510 resultlength
=resultlengthneeded
+1;
511 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
512 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
514 if(U_FAILURE(status
))
516 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
520 if(u_strcmp(result
, temp1
)!=0)
521 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
523 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
527 /*Testing unum_getSymbols() and unum_setSymbols()*/
528 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
529 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
531 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
532 if(status
==U_BUFFER_OVERFLOW_ERROR
)
535 resultlength
=resultlengthneeded
+1;
536 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
537 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
539 if(U_FAILURE(status
))
541 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
545 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
546 if(U_FAILURE(status
))
548 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
553 /*getting the symbols of cur_def */
554 /*set the symbols of cur_frpattern to cur_def */
555 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
557 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
558 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
559 if(U_FAILURE(status
))
561 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
565 /*format to check the result */
567 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
568 if(status
==U_BUFFER_OVERFLOW_ERROR
)
571 resultlength
=resultlengthneeded
+1;
572 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
573 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
575 if(U_FAILURE(status
))
577 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
580 if(U_FAILURE(status
)){
581 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
583 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
585 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
587 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
588 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
589 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
591 log_err("Fail: error in getting symbols\n");
594 log_verbose("Pass: get and set symbols successful\n");
597 /*format and check with the previous result */
600 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
601 if(status
==U_BUFFER_OVERFLOW_ERROR
)
604 resultlength
=resultlengthneeded
+1;
605 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
607 if(U_FAILURE(status
))
609 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
612 * This test fails because we have not called unum_applyPattern().
613 * Currently, such an applyPattern() does not exist on the C API, and
614 * we have jitterbug 411 for it.
615 * Since it is close to the 1.5 release, I (markus) am disabling this test just
616 * for this release (I added the test itself only last week).
617 * For the next release, we need to fix this.
618 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
620 if(u_strcmp(result
, temp1
) != 0) {
621 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
629 /* Testing unum_get/setSymbol() */
630 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
631 symbol
[0] = (UChar
)(0x41 + i
);
632 symbol
[1] = (UChar
)(0x61 + i
);
633 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
634 if(U_FAILURE(status
)) {
635 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
639 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
640 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, UPRV_LENGTHOF(symbol
), &status
);
641 if(U_FAILURE(status
)) {
642 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
645 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
646 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
649 /*try getting from a bogus symbol*/
650 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, UPRV_LENGTHOF(symbol
), &status
);
651 if(U_SUCCESS(status
)){
652 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
654 if(U_FAILURE(status
)){
655 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
656 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
661 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
662 log_verbose("\nTesting getting and setting text attributes\n");
664 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
665 if(U_FAILURE(status
))
667 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
669 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
670 if(U_FAILURE(status
))
672 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
674 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
675 if(U_FAILURE(status
))
677 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
679 if(u_strcmp(suffix
,temp
)!=0)
680 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
682 log_verbose("Pass: setting and getting suffix works fine\n");
683 /*set it back to normal */
684 u_uastrcpy(temp
,"$");
685 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
687 /*checking some more text setter conditions */
688 u_uastrcpy(prefix
, "+");
689 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
690 if(U_FAILURE(status
))
692 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
694 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
695 if(U_FAILURE(status
))
697 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
700 if(u_strcmp(prefix
, temp
)!=0)
701 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
703 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
705 u_uastrcpy(prefix
, "+");
706 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
707 if(U_FAILURE(status
))
709 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
711 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
712 if(U_FAILURE(status
))
714 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
716 if(u_strcmp(prefix
, temp
)!=0)
717 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
719 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
721 u_uastrcpy(suffix
, "+");
722 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
723 if(U_FAILURE(status
))
725 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
728 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
729 if(U_FAILURE(status
))
731 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
733 if(u_strcmp(suffix
, temp
)!=0)
734 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
736 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
738 u_uastrcpy(suffix
, "++");
739 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
740 if(U_FAILURE(status
))
742 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
745 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
746 if(U_FAILURE(status
))
748 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
750 if(u_strcmp(suffix
, temp
)!=0)
751 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
753 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
755 /*Testing unum_getAttribute and unum_setAttribute() */
756 log_verbose("\nTesting get and set Attributes\n");
757 attr
=UNUM_GROUPING_SIZE
;
758 newvalue
=unum_getAttribute(def
, attr
);
760 unum_setAttribute(def
, attr
, newvalue
);
761 if(unum_getAttribute(def
,attr
)!=2)
762 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
764 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
766 attr
=UNUM_MULTIPLIER
;
767 newvalue
=unum_getAttribute(def
, attr
);
769 unum_setAttribute(def
, attr
, newvalue
);
770 if(unum_getAttribute(def
,attr
) != 8)
771 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
773 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
775 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
776 newvalue
=unum_getAttribute(def
, attr
);
778 unum_setAttribute(def
, attr
, newvalue
);
779 if(unum_getAttribute(def
,attr
) != 2)
780 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
781 unum_getAttribute(def
,attr
));
783 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
785 /*testing set and get Attributes extensively */
786 log_verbose("\nTesting get and set attributes extensively\n");
787 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
789 newvalue
=unum_getAttribute(fr
, attr
);
790 unum_setAttribute(def
, attr
, newvalue
);
791 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
792 log_err("error in setting and getting attributes\n");
794 log_verbose("Pass: attributes set and retrieved successfully\n");
797 /*testing spellout format to make sure we can use it successfully.*/
798 log_verbose("\nTesting spellout format\n");
801 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
802 for (i
= 0; i
< UPRV_LENGTHOF(values
); ++i
) {
805 int32_t value
= values
[i
];
806 status
= U_ZERO_ERROR
;
807 len
= unum_format(spellout_def
, value
, buffer
, UPRV_LENGTHOF(buffer
), NULL
, &status
);
808 if(U_FAILURE(status
)) {
809 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
813 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
814 log_verbose("formatted %d as '%s', length: %d\n", value
, aescstrdup(buffer
, len
), len
);
816 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
817 if (U_FAILURE(status
)) {
818 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
819 } else if (parseResult
!= value
) {
820 log_err("unum_format result %d != value %d\n", parseResult
, value
);
826 log_err("Spellout format is unavailable\n");
829 { /* Test for ticket #7079 */
830 UNumberFormat
* dec_en
;
831 UChar groupingSep
[] = { 0 };
832 UChar numPercent
[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
833 double parseResult
= 0.0;
836 dec_en
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
837 unum_setAttribute(dec_en
, UNUM_LENIENT_PARSE
, 0);
838 unum_setSymbol(dec_en
, UNUM_GROUPING_SEPARATOR_SYMBOL
, groupingSep
, 0, &status
);
839 parseResult
= unum_parseDouble(dec_en
, numPercent
, -1, NULL
, &status
);
840 /* Without the fix in #7079, the above call will hang */
841 if ( U_FAILURE(status
) || parseResult
!= 12.0 ) {
842 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
843 myErrorName(status
), parseResult
);
845 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
850 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
851 to verify that it is taking the pure decimal path. */
853 const char *bdpattern
= "#,##0.#########";
854 const char *numInitial
= "12345678900987654321.1234567896";
855 const char *numFormatted
= "12,345,678,900,987,654,321.12345679";
856 const char *parseExpected
= "12345678900987654321.12345679";
857 const char *parseExpected2
= "345678900987654321.12345679";
858 int32_t resultSize
= 0;
859 int32_t parsePos
= 0; /* Output parameter for Parse operations. */
860 #define DESTCAPACITY 100
861 UChar dest
[DESTCAPACITY
];
862 char desta
[DESTCAPACITY
];
863 UFieldPosition fieldPos
= {0};
867 status
= U_ZERO_ERROR
;
868 u_uastrcpy(dest
, bdpattern
);
869 fmt
= unum_open(UNUM_PATTERN_DECIMAL
, dest
, -1, "en", NULL
/*parseError*/, &status
);
870 if (U_FAILURE(status
)) log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
872 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, NULL
, &status
);
873 if (U_FAILURE(status
)) {
874 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
876 u_austrncpy(desta
, dest
, DESTCAPACITY
);
877 if (strcmp(numFormatted
, desta
) != 0) {
878 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
879 __FILE__
, __LINE__
, numFormatted
, desta
);
881 if (strlen(numFormatted
) != resultSize
) {
882 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
883 __FILE__
, __LINE__
, strlen(numFormatted
), resultSize
);
886 /* Format with a FieldPosition parameter */
888 fieldPos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
889 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, &fieldPos
, &status
);
890 if (U_FAILURE(status
)) {
891 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
893 u_austrncpy(desta
, dest
, DESTCAPACITY
);
894 if (strcmp(numFormatted
, desta
) != 0) {
895 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
896 __FILE__
, __LINE__
, numFormatted
, desta
);
898 if (fieldPos
.beginIndex
!= 26) { /* index of "." in formatted number */
899 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
900 __FILE__
, __LINE__
, 0, fieldPos
.beginIndex
);
902 if (fieldPos
.endIndex
!= 27) {
903 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
904 __FILE__
, __LINE__
, 0, fieldPos
.endIndex
);
909 status
= U_ZERO_ERROR
;
910 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
911 resultSize
= unum_parseDecimal(fmt
, dest
, -1, NULL
, desta
, DESTCAPACITY
, &status
);
912 if (U_FAILURE(status
)) {
913 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
915 if (uprv_strcmp(parseExpected
, desta
) != 0) {
916 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
917 __FILE__
, __LINE__
, parseExpected
, desta
);
919 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
920 __FILE__
, __LINE__
, desta
);
922 if (strlen(parseExpected
) != resultSize
) {
923 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
924 __FILE__
, __LINE__
, strlen(parseExpected
), resultSize
);
927 /* Parse with a parsePos parameter */
929 status
= U_ZERO_ERROR
;
930 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
931 parsePos
= 3; /* 12,345,678,900,987,654,321.12345679 */
932 /* start parsing at the the third char */
933 resultSize
= unum_parseDecimal(fmt
, dest
, -1, &parsePos
, desta
, DESTCAPACITY
, &status
);
934 if (U_FAILURE(status
)) {
935 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
937 if (strcmp(parseExpected2
, desta
) != 0) { /* "345678900987654321.12345679" */
938 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
939 __FILE__
, __LINE__
, parseExpected2
, desta
);
941 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
942 __FILE__
, __LINE__
, desta
);
944 if (strlen(numFormatted
) != parsePos
) {
945 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
946 __FILE__
, __LINE__
, strlen(parseExpected
), parsePos
);
952 status
= U_ZERO_ERROR
;
953 /* Test invalid symbol argument */
955 int32_t badsymbolLarge
= UNUM_FORMAT_SYMBOL_COUNT
+ 1;
956 int32_t badsymbolSmall
= -1;
958 int32_t valueLength
= 10;
959 UNumberFormat
*fmt
= unum_open(UNUM_DEFAULT
, NULL
, 0, NULL
, NULL
, &status
);
960 if (U_FAILURE(status
)) {
961 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
963 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, NULL
, 0, &status
);
964 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
966 status
= U_ZERO_ERROR
;
967 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, NULL
, 0, &status
);
968 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
970 status
= U_ZERO_ERROR
;
971 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, value
, valueLength
, &status
);
972 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
974 status
= U_ZERO_ERROR
;
975 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, value
, valueLength
, &status
);
976 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
983 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
990 unum_close(spellout_def
);
992 unum_close(cur_frpattern
);
997 static void TestParseZero(void)
999 UErrorCode errorCode
= U_ZERO_ERROR
;
1000 UChar input
[] = {0x30, 0}; /* Input text is decimal '0' */
1001 UChar pat
[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
1005 UNumberFormat
* unum
= unum_open( UNUM_DECIMAL
/*or UNUM_DEFAULT*/, NULL
, -1, NULL
, NULL
, &errorCode
);
1007 UNumberFormat
* unum
= unum_open( UNUM_PATTERN_DECIMAL
/*needs pattern*/, pat
, -1, NULL
, NULL
, &errorCode
);
1010 dbl
= unum_parseDouble( unum
, input
, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode
);
1011 if (U_FAILURE(errorCode
)) {
1012 log_data_err("Result - %s\n", u_errorName(errorCode
));
1014 log_verbose("Double: %f\n", dbl
);
1019 static const UChar dollars2Sym
[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
1020 static const UChar dollars4Sym
[] = { 0x24,0x34,0 }; /* $4 */
1021 static const UChar dollarsUS4Sym
[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
1022 static const UChar dollars9Sym
[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
1023 static const UChar pounds3Sym
[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
1024 static const UChar pounds5Sym
[] = { 0xA3,0x35,0 }; /* [POUND]5 */
1025 static const UChar pounds7Sym
[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
1026 static const UChar euros4Sym
[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
1027 static const UChar euros6Sym
[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
1028 static const UChar euros8Sym
[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
1029 static const UChar dollars4PluEn
[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
1030 static const UChar pounds5PluEn
[] = { 0x35,0x20,0x42,0x72,0x69,0x74,0x69,0x73,0x68,0x20,0x70,0x6F,0x75,0x6E,0x64,0x73,0x20,0x73,0x74,0x65,0x72,0x6C,0x69,0x6E,0x67,0 }; /* 5 British pounds sterling */
1031 static const UChar euros8PluEn
[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
1032 static const UChar euros6PluFr
[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
1035 const char * locale
;
1036 const char * descrip
;
1037 const UChar
* currStr
;
1038 const UChar
* plurStr
;
1039 UErrorCode parsDoubExpectErr
;
1040 int32_t parsDoubExpectPos
;
1041 double parsDoubExpectVal
;
1042 UErrorCode parsCurrExpectErr
;
1043 int32_t parsCurrExpectPos
;
1044 double parsCurrExpectVal
;
1045 const char * parsCurrExpectCurr
;
1046 } ParseCurrencyItem
;
1048 static const ParseCurrencyItem parseCurrencyItems
[] = {
1049 { "en_US", "dollars2", dollars2Sym
, NULL
, U_ZERO_ERROR
, 5, 2.0, U_ZERO_ERROR
, 5, 2.0, "USD" },
1050 { "en_US", "dollars4", dollars4Sym
, dollars4PluEn
, U_ZERO_ERROR
, 2, 4.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1051 { "en_US", "dollars9", dollars9Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1052 { "en_US", "pounds3", pounds3Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1053 { "en_US", "pounds5", pounds5Sym
, pounds5PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1054 { "en_US", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1055 { "en_US", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1057 { "en_GB", "pounds3", pounds3Sym
, NULL
, U_ZERO_ERROR
, 5, 3.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1058 { "en_GB", "pounds5", pounds5Sym
, pounds5PluEn
, U_ZERO_ERROR
, 2, 5.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1059 { "en_GB", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1060 { "en_GB", "euros4", euros4Sym
, NULL
, U_PARSE_ERROR
, 4, 0.0, U_PARSE_ERROR
, 4, 0.0, "" },
1061 { "en_GB", "euros6", euros6Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1062 { "en_GB", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1063 { "en_GB", "dollars4", dollarsUS4Sym
,dollars4PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 4, 4.0, "USD" },
1065 { "fr_FR", "euros4", euros4Sym
, NULL
, U_ZERO_ERROR
, 6, 4.0, U_ZERO_ERROR
, 6, 4.0, "EUR" },
1066 { "fr_FR", "euros6", euros6Sym
, euros6PluFr
, U_ZERO_ERROR
, 3, 6.0, U_ZERO_ERROR
, 3, 6.0, "EUR" },
1067 { "fr_FR", "euros8", euros8Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1068 { "fr_FR", "dollars2", dollars2Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1069 { "fr_FR", "dollars4", dollars4Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1071 { NULL
, NULL
, NULL
, NULL
, 0, 0, 0.0, 0, 0, 0.0, NULL
}
1074 static void TestParseCurrency()
1076 const ParseCurrencyItem
* itemPtr
;
1077 for (itemPtr
= parseCurrencyItems
; itemPtr
->locale
!= NULL
; ++itemPtr
) {
1078 UNumberFormat
* unum
;
1085 status
= U_ZERO_ERROR
;
1086 unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1087 if (U_SUCCESS(status
)) {
1088 const UChar
* currStr
= itemPtr
->currStr
;
1089 status
= U_ZERO_ERROR
;
1091 parseVal
= unum_parseDouble(unum
, currStr
, -1, &parsePos
, &status
);
1092 if (status
!= itemPtr
->parsDoubExpectErr
|| parsePos
!= itemPtr
->parsDoubExpectPos
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1093 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1094 itemPtr
->locale
, itemPtr
->descrip
,
1095 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectPos
, itemPtr
->parsDoubExpectVal
,
1096 u_errorName(status
), parsePos
, parseVal
);
1098 status
= U_ZERO_ERROR
;
1101 parseVal
= unum_parseDoubleCurrency(unum
, currStr
, -1, &parsePos
, parseCurr
, &status
);
1102 u_austrncpy(parseCurrB
, parseCurr
, 4);
1103 if (status
!= itemPtr
->parsCurrExpectErr
|| parsePos
!= itemPtr
->parsCurrExpectPos
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1104 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1105 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1106 itemPtr
->locale
, itemPtr
->descrip
,
1107 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectPos
, itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1108 u_errorName(status
), parsePos
, parseVal
, parseCurrB
);
1112 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1115 if (itemPtr
->plurStr
!= NULL
) {
1116 status
= U_ZERO_ERROR
;
1117 unum
= unum_open(UNUM_CURRENCY_PLURAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1118 if (U_SUCCESS(status
)) {
1119 status
= U_ZERO_ERROR
;
1121 parseVal
= unum_parseDouble(unum
, itemPtr
->plurStr
, -1, &parsePos
, &status
);
1122 if (status
!= itemPtr
->parsDoubExpectErr
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1123 log_err("UNUM_CURRENCY parseDouble Plural %s/%s, expect %s val %.1f, get %s val %.1f\n",
1124 itemPtr
->locale
, itemPtr
->descrip
,
1125 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectVal
,
1126 u_errorName(status
), parseVal
);
1128 status
= U_ZERO_ERROR
;
1131 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->plurStr
, -1, &parsePos
, parseCurr
, &status
);
1132 u_austrncpy(parseCurrB
, parseCurr
, 4);
1133 if (status
!= itemPtr
->parsCurrExpectErr
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1134 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1135 log_err("UNUM_CURRENCY parseDoubleCurrency Plural %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1136 itemPtr
->locale
, itemPtr
->descrip
,
1137 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1138 u_errorName(status
), parseVal
, parseCurrB
);
1142 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1149 const char * testname
;
1150 const char * locale
;
1152 const UChar
* source
;
1159 static const UChar ustr_zh50d
[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1160 static const UChar ustr_zh05a
[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1161 static const UChar ustr_zh05d
[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1163 static const NumParseTestItem altnumParseTests
[] = {
1164 /* name loc lenent src start val end status */
1165 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_USING_DEFAULT_WARNING
},
1166 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_USING_DEFAULT_WARNING
},
1167 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_USING_DEFAULT_WARNING
},
1168 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1171 static void TestParseAltNum(void)
1173 const NumParseTestItem
* testPtr
;
1174 for (testPtr
= altnumParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1175 UErrorCode status
= U_ZERO_ERROR
;
1176 int32_t value
, position
= testPtr
->startPos
;
1177 UNumberFormat
*nf
= unum_open(UNUM_DECIMAL
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1178 if (U_FAILURE(status
)) {
1179 log_err_status(status
, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1182 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1183 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1184 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1185 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1186 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1187 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1188 value
, position
, myErrorName(status
) );
1194 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1195 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1196 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1197 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1198 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1199 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1200 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
1201 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1202 static const UChar ustr_zh50s
[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1203 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1204 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1205 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1207 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1209 static const NumParseTestItem spelloutParseTests
[] = {
1210 /* name loc lenent src start val end status */
1211 { "en0", "en", FALSE
, ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
1212 { "en0", "en", FALSE
, ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
1213 { "en0", "ja", FALSE
, ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
1214 #if NUMERIC_STRINGS_NOT_PARSEABLE
1215 { "123", "en", FALSE
, ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
1217 { "123", "en", FALSE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1219 { "123L", "en", TRUE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1220 { "en123", "en", FALSE
, ustr_en123
, 0, 123, 24, U_ZERO_ERROR
},
1221 { "en123", "en", FALSE
, ustr_en123
, 12, 23, 24, U_ZERO_ERROR
},
1222 { "en123", "fr", FALSE
, ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
1223 { "fr123", "fr", FALSE
, ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
1224 { "fr123", "fr", FALSE
, ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
1225 { "fr123", "en", FALSE
, ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
1226 { "ja123", "ja", FALSE
, ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
1227 { "ja123", "ja", FALSE
, ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
1228 { "ja123", "fr", FALSE
, ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
1229 { "zh,50s", "zh", FALSE
, ustr_zh50s
, 0, 50, 2, U_ZERO_ERROR
},
1230 // from ICU50m2, NUMERIC_STRINGS_NOT_PARSEABLE no longer affects the next three
1231 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1232 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1233 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1234 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1235 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1236 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1237 { "zh,50dL","zh", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1238 { "zh,05aL","zh", TRUE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1239 { "zh,05dL","zh", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1240 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1243 static void TestSpelloutNumberParse()
1245 const NumParseTestItem
* testPtr
;
1246 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1247 UErrorCode status
= U_ZERO_ERROR
;
1248 int32_t value
, position
= testPtr
->startPos
;
1249 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1250 if (U_FAILURE(status
)) {
1251 log_err_status(status
, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1254 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1255 status
= U_ZERO_ERROR
;
1256 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1257 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1258 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1259 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1260 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1261 value
, position
, myErrorName(status
) );
1267 static void TestSignificantDigits()
1270 int32_t resultlengthneeded
;
1271 int32_t resultlength
;
1272 UErrorCode status
= U_ZERO_ERROR
;
1273 UChar
*result
= NULL
;
1275 double d
= 123456.789;
1277 u_uastrcpy(temp
, "###0.0#");
1278 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, "en", NULL
, &status
);
1279 if (U_FAILURE(status
)) {
1280 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1283 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1284 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
1286 u_uastrcpy(temp
, "123457");
1288 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
1289 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1291 status
=U_ZERO_ERROR
;
1292 resultlength
=resultlengthneeded
+1;
1293 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1294 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
1296 if(U_FAILURE(status
))
1298 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1301 if(u_strcmp(result
, temp
)==0)
1302 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1304 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1309 static void TestSigDigRounding()
1311 UErrorCode status
= U_ZERO_ERROR
;
1312 UChar expected
[128];
1319 fmt
=unum_open(UNUM_DECIMAL
, NULL
, 0, "en", NULL
, &status
);
1320 if (U_FAILURE(status
)) {
1321 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1324 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, FALSE
);
1325 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1326 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2);
1327 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1329 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_UP
);
1330 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, 20.0);
1332 (void)unum_formatDouble(fmt
, d
, result
, UPRV_LENGTHOF(result
), NULL
, &status
);
1333 if(U_FAILURE(status
))
1335 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1339 u_uastrcpy(expected
, "140");
1340 if(u_strcmp(result
, expected
)!=0)
1341 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1
, result
), u_austrcpy(temp2
, expected
) );
1346 static void TestNumberFormatPadding()
1352 UErrorCode status
=U_ZERO_ERROR
;
1353 int32_t resultlength
;
1354 int32_t resultlengthneeded
;
1355 UNumberFormat
*pattern
;
1357 double d
= -10456.37;
1358 UFieldPosition pos1
;
1361 /* create a number format using unum_openPattern(....)*/
1362 log_verbose("\nTesting unum_openPattern() with padding\n");
1363 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
1364 status
=U_ZERO_ERROR
;
1365 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
1366 if(U_SUCCESS(status
))
1368 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );
1372 unum_close(pattern
);
1375 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1376 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
1377 u_uastrcpy(temp2
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // output pattern, ICU 61 behavior
1378 status
=U_ZERO_ERROR
;
1379 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
1380 if(U_FAILURE(status
))
1382 log_err_status(status
, "error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
1385 log_verbose("Pass: padding unum_openPattern() works fine\n");
1387 /*test for unum_toPattern()*/
1388 log_verbose("\nTesting padding unum_toPattern()\n");
1390 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
1391 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1393 status
=U_ZERO_ERROR
;
1394 resultlength
=resultlengthneeded
+1;
1395 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1396 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
1398 if(U_FAILURE(status
))
1400 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
1404 if(u_strncmp(result
, temp2
, resultlengthneeded
)!=0) {
1406 "FAIL: Error in extracting the padding pattern using unum_toPattern(): %d: %s != %s\n",
1411 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1415 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1416 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
1418 pos1
.field
= UNUM_FRACTION_FIELD
;
1419 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
1420 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1422 status
=U_ZERO_ERROR
;
1423 resultlength
=resultlengthneeded
+1;
1424 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1425 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
1427 if(U_FAILURE(status
))
1429 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
1433 if(u_strcmp(result
, temp1
)==0)
1434 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1436 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1437 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
1438 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1440 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1441 pos1
.beginIndex
, pos1
.endIndex
);
1444 /* Testing unum_parse() and unum_parseDouble() */
1445 log_verbose("\nTesting padding unum_parseDouble()\n");
1447 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
1448 if(U_FAILURE(status
))
1450 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
1454 log_err("Fail: Error in padding parsing\n");
1456 log_verbose("Pass: padding parsing successful\n");
1461 unum_close(pattern
);
1465 withinErr(double a
, double b
, double err
) {
1466 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
1469 static void TestInt64Format() {
1473 UErrorCode status
= U_ZERO_ERROR
;
1474 const double doubleInt64Max
= (double)U_INT64_MAX
;
1475 const double doubleInt64Min
= (double)U_INT64_MIN
;
1476 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
1482 /* create a number format using unum_openPattern(....) */
1483 log_verbose("\nTesting Int64Format\n");
1484 u_uastrcpy(temp1
, "#.#E0");
1485 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), "en_US", NULL
, &status
);
1486 if(U_FAILURE(status
)) {
1487 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status
));
1489 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1490 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1491 if (U_FAILURE(status
)) {
1492 log_err("error in unum_format(): %s\n", myErrorName(status
));
1494 log_verbose("format int64max: '%s'\n", result
);
1496 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1497 if (status
!= U_INVALID_FORMAT_ERROR
) {
1498 log_err("parse didn't report error: %s\n", myErrorName(status
));
1499 } else if (val32
!= INT32_MAX
) {
1500 log_err("parse didn't pin return value, got: %d\n", val32
);
1503 status
= U_ZERO_ERROR
;
1505 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1506 if (U_FAILURE(status
)) {
1507 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1508 } else if (val64
!= U_INT64_MAX
) {
1509 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1512 status
= U_ZERO_ERROR
;
1514 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1515 if (U_FAILURE(status
)) {
1516 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1517 } else if (valDouble
!= doubleInt64Max
) {
1518 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1522 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1523 if (U_FAILURE(status
)) {
1524 log_err("error in unum_format(): %s\n", myErrorName(status
));
1526 log_verbose("format int64min: '%s'\n", result
);
1528 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1529 if (status
!= U_INVALID_FORMAT_ERROR
) {
1530 log_err("parse didn't report error: %s\n", myErrorName(status
));
1531 } else if (val32
!= INT32_MIN
) {
1532 log_err("parse didn't pin return value, got: %d\n", val32
);
1535 status
= U_ZERO_ERROR
;
1537 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1538 if (U_FAILURE(status
)) {
1539 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1540 } else if (val64
!= U_INT64_MIN
) {
1541 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1544 status
= U_ZERO_ERROR
;
1546 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1547 if (U_FAILURE(status
)) {
1548 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1549 } else if (valDouble
!= doubleInt64Min
) {
1550 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1554 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1555 if (U_FAILURE(status
)) {
1556 log_err("error in unum_format(): %s\n", myErrorName(status
));
1558 log_verbose("format doubleBig: '%s'\n", result
);
1560 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1561 if (status
!= U_INVALID_FORMAT_ERROR
) {
1562 log_err("parse didn't report error: %s\n", myErrorName(status
));
1563 } else if (val32
!= INT32_MAX
) {
1564 log_err("parse didn't pin return value, got: %d\n", val32
);
1567 status
= U_ZERO_ERROR
;
1569 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1570 if (status
!= U_INVALID_FORMAT_ERROR
) {
1571 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1572 } else if (val64
!= U_INT64_MAX
) {
1573 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1576 status
= U_ZERO_ERROR
;
1578 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1579 if (U_FAILURE(status
)) {
1580 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1581 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1582 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1586 u_uastrcpy(result
, "5.06e-27");
1588 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1589 if (U_FAILURE(status
)) {
1590 log_err("parseDouble() returned error: %s\n", myErrorName(status
));
1591 } else if (!withinErr(valDouble
, 5.06e-27, 1e-15)) {
1592 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble
);
1599 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1602 int32_t BUFSIZE
= UPRV_LENGTHOF(buffer
);
1604 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1608 for (i
= 0; i
< UPRV_LENGTHOF(vals
); ++i
) {
1609 UErrorCode status
= U_ZERO_ERROR
;
1610 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1611 if (U_FAILURE(status
)) {
1612 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1614 u_austrcpy(temp
, buffer
);
1615 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1619 /* check APIs now */
1621 UErrorCode status
= U_ZERO_ERROR
;
1623 u_uastrcpy(buffer
, "#,##0.0#");
1624 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1625 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1626 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1631 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1632 log_verbose("lenient: 0x%x\n", isLenient
);
1633 if (isLenient
!= FALSE
) {
1634 log_err("didn't expect lenient value: %d\n", isLenient
);
1637 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1638 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1639 if (isLenient
!= TRUE
) {
1640 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1646 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1648 log_err("didn't expect double attribute\n");
1650 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1651 if ((val
== -1) == isDecimal
) {
1652 log_err("didn't expect -1 rounding increment\n");
1654 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1655 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1656 if (isDecimal
&& (val2
- val
!= .5)) {
1657 log_err("set rounding increment had no effect on decimal format");
1662 UErrorCode status
= U_ZERO_ERROR
;
1663 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1664 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1665 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1667 if (U_SUCCESS(status
)) {
1668 u_austrcpy(temp
, buffer
);
1669 log_verbose("default ruleset: '%s'\n", temp
);
1672 status
= U_ZERO_ERROR
;
1673 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1674 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1675 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1677 if (U_SUCCESS(status
)) {
1678 u_austrcpy(temp
, buffer
);
1679 log_verbose("public rulesets: '%s'\n", temp
);
1681 /* set the default ruleset to the first one found, and retry */
1684 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1687 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1688 if (U_FAILURE(status
)) {
1689 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1691 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1692 if (U_FAILURE(status
)) {
1693 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1694 } else if (len2
!= i
) {
1695 u_austrcpy(temp
, buffer
);
1696 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1698 for (i
= 0; i
< UPRV_LENGTHOF(vals
); ++i
) {
1699 status
= U_ZERO_ERROR
;
1700 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1701 if (U_FAILURE(status
)) {
1702 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1704 u_austrcpy(temp
, buffer
);
1705 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1716 UErrorCode status
= U_ZERO_ERROR
;
1717 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1718 if (U_SUCCESS(status
)) {
1719 u_austrcpy(temp
, buffer
);
1720 log_verbose("pattern: '%s'\n", temp
);
1721 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1722 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1724 log_verbose("pattern too long to display\n");
1729 UErrorCode status
= U_ZERO_ERROR
;
1730 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1731 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1732 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1735 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1736 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1737 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1742 static void TestNonExistentCurrency() {
1743 UNumberFormat
*format
;
1744 UErrorCode status
= U_ZERO_ERROR
;
1745 UChar currencySymbol
[8];
1746 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1748 /* Get a non-existent currency and make sure it returns the correct currency code. */
1749 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1750 if (format
== NULL
|| U_FAILURE(status
)) {
1751 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status
));
1754 unum_getSymbol(format
,
1755 UNUM_CURRENCY_SYMBOL
,
1757 UPRV_LENGTHOF(currencySymbol
),
1759 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1760 log_err("unum_open set the currency to QQQ\n");
1766 static void TestRBNFFormat() {
1770 UChar tempUChars
[512];
1771 UNumberFormat
*formats
[5];
1772 int COUNT
= UPRV_LENGTHOF(formats
);
1775 for (i
= 0; i
< COUNT
; ++i
) {
1780 status
= U_ZERO_ERROR
;
1781 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1782 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1783 if (U_FAILURE(status
)) {
1784 log_err_status(status
, "unable to open decimal pattern -> %s\n", u_errorName(status
));
1788 status
= U_ZERO_ERROR
;
1789 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1790 if (U_FAILURE(status
)) {
1791 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1795 status
= U_ZERO_ERROR
;
1796 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1797 if (U_FAILURE(status
)) {
1798 log_err_status(status
, "unable to open ordinal -> %s\n", u_errorName(status
));
1802 status
= U_ZERO_ERROR
;
1803 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1804 if (U_FAILURE(status
)) {
1805 log_err_status(status
, "unable to open duration %s\n", u_errorName(status
));
1809 status
= U_ZERO_ERROR
;
1813 "x.x: << point >>;\n"
1814 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1815 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1816 "seventeen; eighteen; nineteen;\n"
1817 "20: twenty[->>];\n"
1818 "30: thirty[->>];\n"
1822 "70: seventy[->>];\n"
1823 "80: eighty[->>];\n"
1824 "90: ninety[->>];\n"
1826 u_uastrcpy(tempUChars
,
1829 "20: twenty[ and change];\n"
1830 "30: thirty[ and change];\n"
1831 "40: forty[ and change];\n"
1832 "50: fifty[ and change];\n"
1833 "60: sixty[ and change];\n"
1834 "70: seventy[ and change];\n"
1835 "80: eighty[ and change];\n"
1836 "90: ninety[ and change];\n"
1840 "x.x: << point something;\n"
1842 "20: some reasonable number;\n"
1843 "100: some substantial number;\n"
1844 "100,000,000: some huge number;\n");
1845 /* This is to get around some compiler warnings about char * string length. */
1846 u_strcat(pat
, tempUChars
);
1847 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1848 if (U_FAILURE(status
)) {
1849 log_err_status(status
, "unable to open rulebased pattern -> %s\n", u_errorName(status
));
1851 if (U_FAILURE(status
)) {
1852 log_err_status(status
, "Something failed with %s\n", u_errorName(status
));
1856 for (i
= 0; i
< COUNT
; ++i
) {
1857 log_verbose("\n\ntesting format %d\n", i
);
1858 test_fmt(formats
[i
], (UBool
)(i
== 0));
1861 #define FORMAT_BUF_CAPACITY 64
1863 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1865 double nanvalue
= uprv_getNaN();
1866 status
= U_ZERO_ERROR
;
1867 len
= unum_formatDouble(formats
[1], nanvalue
, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1868 if (U_FAILURE(status
)) {
1869 log_err_status(status
, "unum_formatDouble NAN failed with %s\n", u_errorName(status
));
1871 UChar nansym
[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1872 if ( len
!= 3 || u_strcmp(fmtbuf
, nansym
) != 0 ) {
1873 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1878 for (i
= 0; i
< COUNT
; ++i
) {
1879 unum_close(formats
[i
]);
1883 static void TestRBNFRounding() {
1884 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1885 UChar expectedBuf
[FORMAT_BUF_CAPACITY
];
1887 UErrorCode status
= U_ZERO_ERROR
;
1888 UNumberFormat
* fmt
= unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", NULL
, &status
);
1889 if (U_FAILURE(status
)) {
1890 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1893 len
= unum_formatDouble(fmt
, 10.123456789, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1894 if (U_FAILURE(status
)) {
1895 log_err_status(status
, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status
));
1897 u_uastrcpy(expectedBuf
, "ten point one two three four five six seven eight nine");
1898 if (u_strcmp(expectedBuf
, fmtbuf
) != 0) {
1899 log_err("Wrong result for unrounded value\n");
1901 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 3);
1902 if (unum_getAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
) != 3) {
1903 log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
));
1905 if (unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
) != UNUM_ROUND_UNNECESSARY
) {
1906 log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
));
1908 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_HALFUP
);
1909 if (unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
) != UNUM_ROUND_HALFUP
) {
1910 log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
));
1912 len
= unum_formatDouble(fmt
, 10.123456789, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1913 if (U_FAILURE(status
)) {
1914 log_err_status(status
, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status
));
1916 u_uastrcpy(expectedBuf
, "ten point one two three");
1917 if (u_strcmp(expectedBuf
, fmtbuf
) != 0) {
1919 u_austrcpy(temp
, fmtbuf
);
1920 log_err("Wrong result for rounded value. Got: %s\n", temp
);
1925 static void TestCurrencyRegression(void) {
1927 I've found a case where unum_parseDoubleCurrency is not doing what I
1928 expect. The value I pass in is $1234567890q123460000.00 and this
1929 returns with a status of zero error & a parse pos of 22 (I would
1930 expect a parse error at position 11).
1932 I stepped into DecimalFormat::subparse() and it looks like it parses
1933 the first 10 digits and then stops parsing at the q but doesn't set an
1934 error. Then later in DecimalFormat::parse() the value gets crammed
1935 into a long (which greatly truncates the value).
1937 This is very problematic for me 'cause I try to remove chars that are
1938 invalid but this allows my users to enter bad chars and truncates
1948 UErrorCode status
= U_ZERO_ERROR
;
1949 const int32_t expected
= 11;
1952 u_uastrcpy(buf
, "$1234567890q643210000.00");
1953 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1955 if(U_FAILURE(status
)) {
1956 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status
));
1960 status
= U_ZERO_ERROR
; /* so we can test it later. */
1963 d
= unum_parseDoubleCurrency(cur
,
1966 &pos
, /* 0 = start */
1970 u_austrcpy(acurrency
, currency
);
1972 if(U_FAILURE(status
) || (pos
!= expected
)) {
1973 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1974 expected
, d
, u_errorName(status
), pos
, acurrency
);
1976 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
1982 static void TestTextAttributeCrash(void) {
1983 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
1984 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1985 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1987 UErrorCode status
= U_ZERO_ERROR
;
1988 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
1989 if (U_FAILURE(status
)) {
1990 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status
));
1993 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
1995 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1996 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1998 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
1999 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
2000 if (U_FAILURE(status
)) {
2001 log_err("FAILED 2\n"); exit(1);
2003 log_verbose("attempting to format...\n");
2004 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
2005 if (U_FAILURE(status
) || 64 < used
) {
2006 log_err("Failed formatting %s\n", u_errorName(status
));
2009 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
2010 log_err("Didn't get expected negative result\n");
2012 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
2013 if (U_FAILURE(status
) || 64 < used
) {
2014 log_err("Failed formatting %s\n", u_errorName(status
));
2017 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
2018 log_err("Didn't get expected positive result\n");
2023 static void TestNBSPPatternRtNum(const char *testcase
, int line
, UNumberFormat
*nf
, double myNumber
) {
2024 UErrorCode status
= U_ZERO_ERROR
;
2027 double aNumber
= -1.0;
2028 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
2029 log_verbose("%s:%d: formatted %.2f into %s\n", testcase
, line
, myNumber
, u_austrcpy(tmpbuf
, myString
));
2030 if(U_FAILURE(status
)) {
2031 log_err("%s:%d: failed format of %.2g with %s\n", testcase
, line
, myNumber
, u_errorName(status
));
2034 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
2035 if(U_FAILURE(status
)) {
2036 log_err("%s:%d: failed parse with %s\n", testcase
, line
, u_errorName(status
));
2039 if(uprv_fabs(aNumber
-myNumber
)>.001) {
2040 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
2042 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
2046 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
2047 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, 12345.);
2048 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, -12345.);
2051 static void TestNBSPInPattern(void) {
2052 UErrorCode status
= U_ZERO_ERROR
;
2053 UNumberFormat
* nf
= NULL
;
2054 const char *testcase
;
2057 testcase
="ar_AE UNUM_CURRENCY";
2058 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
2059 if(U_FAILURE(status
) || nf
== NULL
) {
2060 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, testcase
, u_errorName(status
));
2063 TestNBSPPatternRT(testcase
, nf
);
2065 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
2067 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
2069 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
2070 u_unescape(SPECIAL_PATTERN
, pat
, UPRV_LENGTHOF(pat
));
2071 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
2072 if(U_FAILURE(status
)) {
2073 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
2075 TestNBSPPatternRT(testcase
, nf
);
2077 #undef SPECIAL_PATTERN
2079 unum_close(nf
); status
= U_ZERO_ERROR
;
2081 testcase
="ar_AE UNUM_DECIMAL";
2082 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
2083 if(U_FAILURE(status
)) {
2084 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2086 TestNBSPPatternRT(testcase
, nf
);
2087 unum_close(nf
); status
= U_ZERO_ERROR
;
2089 testcase
="ar_AE UNUM_PERCENT";
2090 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
2091 if(U_FAILURE(status
)) {
2092 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2094 TestNBSPPatternRT(testcase
, nf
);
2095 unum_close(nf
); status
= U_ZERO_ERROR
;
2100 static void TestCloneWithRBNF(void) {
2101 UChar pattern
[1024];
2103 UErrorCode status
= U_ZERO_ERROR
;
2105 UChar buffer_cloned
[256];
2108 UNumberFormat
*pform_cloned
;
2109 UNumberFormat
*pform
;
2113 "0.x: >%%millis-only>;\n"
2114 "x.0: <%%duration<;\n"
2115 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2116 "-x: ->>;%%millis-only:\n"
2117 "1000: 00:00.<%%millis<;\n"
2119 "1000: .<%%millis<;\n"
2123 "0: =%%seconds-only=;\n"
2124 "60: =%%min-sec=;\n"
2125 "3600: =%%hr-min-sec=;\n"
2126 "86400/86400: <%%ddaayyss<[, >>];\n"
2127 "%%durationwithmillis:\n"
2128 "0: =%%seconds-only=;\n"
2129 "60: =%%min-sec=;\n"
2130 "3600: =%%hr-min-sec=;\n"
2131 "86400/86400: <%%ddaayyss<, >>;\n");
2141 "3600/60: <0<:>>>;\n"
2147 /* This is to get around some compiler warnings about char * string length. */
2148 u_strcat(pattern
, pat2
);
2150 pform
= unum_open(UNUM_PATTERN_RULEBASED
, pattern
, -1, "en_US", NULL
, &status
);
2151 unum_formatDouble(pform
, 3600, buffer
, 256, NULL
, &status
);
2153 pform_cloned
= unum_clone(pform
,&status
);
2154 unum_formatDouble(pform_cloned
, 3600, buffer_cloned
, 256, NULL
, &status
);
2157 unum_close(pform_cloned
);
2159 if (u_strcmp(buffer
,buffer_cloned
)) {
2160 log_data_err("Result from cloned formatter not identical to the original. Original: %s Cloned: %s - (Are you missing data?)",u_austrcpy(temp1
, buffer
),u_austrcpy(temp2
,buffer_cloned
));
2165 static void TestNoExponent(void) {
2166 UErrorCode status
= U_ZERO_ERROR
;
2174 fmt
= unum_open(UNUM_DECIMAL
, NULL
, -1, "en_US", NULL
, &status
);
2176 if(U_FAILURE(status
) || fmt
== NULL
) {
2177 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
));
2182 u_uastrcpy(str
, cstr
);
2185 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2186 ASSERT_TRUE(pos
==4);
2187 if(U_FAILURE(status
)) {
2188 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2189 } else if(expect
!=num
) {
2190 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2192 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2195 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2197 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2198 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2200 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2204 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2206 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__
, __LINE__
, cstr
);
2207 } else if(num
==expect
) {
2208 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__
, __LINE__
, num
, cstr
);
2210 ASSERT_TRUE(pos
==2);
2212 status
= U_ZERO_ERROR
;
2216 /* ok, now try scientific */
2217 fmt
= unum_open(UNUM_SCIENTIFIC
, NULL
, -1, "en_US", NULL
, &status
);
2218 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status
);
2220 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2223 u_uastrcpy(str
, cstr
);
2226 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2227 ASSERT_TRUE(pos
==4);
2228 if(U_FAILURE(status
)) {
2229 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2230 } else if(expect
!=num
) {
2231 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2233 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2236 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2237 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2239 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2241 // A scientific formatter should parse the exponent even if UNUM_PARSE_NO_EXPONENT is set
2243 u_uastrcpy(str
, cstr
);
2246 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2247 ASSERT_TRUE(pos
==4);
2248 if(U_FAILURE(status
)) {
2249 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2250 } else if(expect
!=num
) {
2251 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2253 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2259 static void TestMaxInt(void) {
2260 UErrorCode status
= U_ZERO_ERROR
;
2261 UChar pattern_hash
[] = { 0x23, 0x00 }; /* "#" */
2262 UChar result1
[1024] = { 0 }, result2
[1024] = { 0 };
2264 UChar expect
[] = { 0x0039, 0x0037, 0 };
2265 UNumberFormat
*fmt
= unum_open(
2266 UNUM_PATTERN_DECIMAL
, /* style */
2267 &pattern_hash
[0], /* pattern */
2268 u_strlen(pattern_hash
), /* patternLength */
2272 if(U_FAILURE(status
) || fmt
== NULL
) {
2273 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, "TestMaxInt", u_errorName(status
));
2277 unum_setAttribute(fmt
, UNUM_MAX_INTEGER_DIGITS
, 2);
2279 status
= U_ZERO_ERROR
;
2281 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2283 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2284 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2287 status
= U_ZERO_ERROR
;
2289 len2
= unum_formatDouble(fmt
, 1997.0, result2
, 1024, NULL
, &status
);
2291 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2292 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2297 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2298 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==0);
2300 unum_setAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
, 1);
2301 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2302 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==1);
2304 status
= U_ZERO_ERROR
;
2305 /* max int digits still '2' */
2306 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2307 ASSERT_TRUE(status
==U_ILLEGAL_ARGUMENT_ERROR
);
2308 status
= U_ZERO_ERROR
;
2310 /* But, formatting 97->'97' works fine. */
2313 len1
= unum_formatInt64(fmt
, 97, result1
, 1024, NULL
, &status
);
2315 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2316 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2319 status
= U_ZERO_ERROR
;
2321 len2
= unum_formatDouble(fmt
, 97.0, result2
, 1024, NULL
, &status
);
2323 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2324 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2331 static void TestUFormattable(void) {
2333 // simple test for API docs
2335 UErrorCode status
= U_ZERO_ERROR
;
2336 UNumberFormat
*unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2337 if(assertSuccessCheck("calling unum_open()", &status
, TRUE
)) {
2338 //! [unum_parseToUFormattable]
2339 const UChar str
[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2341 UFormattable
*ufmt
= ufmt_open(&status
);
2342 unum_parseToUFormattable(unum
, ufmt
, str
, -1, NULL
, &status
);
2343 if (ufmt_isNumeric(ufmt
)) {
2344 result
= ufmt_getLong(ufmt
, &status
); /* == 123 */
2345 } /* else { ... } */
2347 //! [unum_parseToUFormattable]
2348 assertTrue("result == 123", (result
== 123));
2352 // test with explicitly created ufmt_open
2355 UErrorCode status
= U_ZERO_ERROR
;
2357 UNumberFormat
*unum
;
2358 const char *pattern
= "";
2360 ufmt
= ufmt_open(&status
);
2361 unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2362 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status
, TRUE
)) {
2365 log_verbose("-- pattern: %s\n", pattern
);
2366 u_uastrcpy(buffer
, pattern
);
2367 unum_parseToUFormattable(unum
, ufmt
, buffer
, -1, NULL
, &status
);
2368 if(assertSuccess("unum_parseToUFormattable(31337)", &status
)) {
2369 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt
, &status
) == 31337);
2370 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt
, &status
) == UFMT_LONG
);
2371 log_verbose("long = %d\n", ufmt_getLong(ufmt
, &status
));
2372 assertSuccess("ufmt_getLong()", &status
);
2374 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2375 if(assertSuccess("unum_formatUFormattable(31337)", &status
)) {
2376 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2379 pattern
= "3.14159";
2380 log_verbose("-- pattern: %s\n", pattern
);
2381 u_uastrcpy(buffer
, pattern
);
2382 unum_parseToUFormattable(unum
, ufmt
, buffer
, -1, NULL
, &status
);
2383 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status
)) {
2384 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt
, &status
), 3.14159, 1e-15));
2385 assertSuccess("ufmt_getDouble()", &status
);
2386 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt
, &status
) == UFMT_DOUBLE
);
2387 log_verbose("double = %g\n", ufmt_getDouble(ufmt
, &status
));
2389 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2390 if(assertSuccess("unum_formatUFormattable(3.14159)", &status
)) {
2391 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2398 // test with auto-generated ufmt
2401 UErrorCode status
= U_ZERO_ERROR
;
2402 UFormattable
*ufmt
= NULL
;
2403 UNumberFormat
*unum
;
2404 const char *pattern
= "73476730924573500000000"; // weight of the moon, kg
2406 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern
);
2407 u_uastrcpy(buffer
, pattern
);
2409 unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2410 if(assertSuccessCheck("calling unum_open()", &status
, TRUE
)) {
2412 ufmt
= unum_parseToUFormattable(unum
, NULL
, /* will be ufmt_open()'ed for us */
2413 buffer
, -1, NULL
, &status
);
2414 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status
)) {
2415 log_verbose("new formattable allocated at %p\n", (void*)ufmt
);
2416 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt
));
2417 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2418 if(assertSuccess("unum_formatUFormattable(3.14159)", &status
)) {
2419 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2422 log_verbose("double: %g\n", ufmt_getDouble(ufmt
, &status
));
2423 assertSuccess("ufmt_getDouble()", &status
);
2425 log_verbose("long: %ld\n", ufmt_getLong(ufmt
, &status
));
2426 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status
));
2427 // status is now a failure due to ufmt_getLong() above.
2428 // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2433 ufmt_close(ufmt
); // was implicitly opened for us by the first unum_parseToUFormattable()
2441 UBool isAlgorithmic
;
2442 const UChar
* description
;
2446 static const UChar latnDesc
[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2447 static const UChar romanDesc
[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2448 static const UChar arabDesc
[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2449 static const UChar arabextDesc
[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2450 static const UChar hanidecDesc
[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2451 static const UChar hantDesc
[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2452 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2453 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2455 static const NumSysTestItem numSysTestItems
[] = {
2456 //locale numsys radix isAlgo description
2457 { "en", "latn", 10, FALSE
, latnDesc
},
2458 { "en@numbers=roman", "roman", 10, TRUE
, romanDesc
},
2459 { "en@numbers=finance", "latn", 10, FALSE
, latnDesc
},
2460 { "ar-EG", "arab", 10, FALSE
, arabDesc
},
2461 { "fa", "arabext", 10, FALSE
, arabextDesc
},
2462 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE
, hanidecDesc
},
2463 { "zh_Hant@numbers=traditional", "hant", 10, TRUE
, hantDesc
},
2464 { NULL
, NULL
, 0, FALSE
, NULL
},
2466 enum { kNumSysDescripBufMax
= 64 };
2468 static void TestUNumberingSystem(void) {
2469 const NumSysTestItem
* itemPtr
;
2470 UNumberingSystem
* unumsys
;
2471 UEnumeration
* uenum
;
2472 const char * numsys
;
2475 for (itemPtr
= numSysTestItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
2476 status
= U_ZERO_ERROR
;
2477 unumsys
= unumsys_open(itemPtr
->locale
, &status
);
2478 if ( U_SUCCESS(status
) ) {
2479 UChar ubuf
[kNumSysDescripBufMax
];
2480 int32_t ulen
, radix
= unumsys_getRadix(unumsys
);
2481 UBool isAlgorithmic
= unumsys_isAlgorithmic(unumsys
);
2482 numsys
= unumsys_getName(unumsys
);
2483 if ( uprv_strcmp(numsys
, itemPtr
->numsys
) != 0 || radix
!= itemPtr
->radix
|| !isAlgorithmic
!= !itemPtr
->isAlgorithmic
) {
2484 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2485 itemPtr
->locale
, itemPtr
->numsys
, itemPtr
->radix
, itemPtr
->isAlgorithmic
, numsys
, radix
, isAlgorithmic
);
2487 ulen
= unumsys_getDescription(unumsys
, ubuf
, kNumSysDescripBufMax
, &status
);
2488 (void)ulen
; // Suppress variable not used warning.
2489 if ( U_FAILURE(status
) || u_strcmp(ubuf
, itemPtr
->description
) != 0 ) {
2490 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status
));
2492 unumsys_close(unumsys
);
2494 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr
->locale
, myErrorName(status
));
2498 status
= U_ZERO_ERROR
;
2499 uenum
= unumsys_openAvailableNames(&status
);
2500 if ( U_SUCCESS(status
) ) {
2501 int32_t numsysCount
= 0;
2502 // sanity check for a couple of number systems that must be in the enumeration
2503 UBool foundLatn
= FALSE
;
2504 UBool foundArab
= FALSE
;
2505 while ( (numsys
= uenum_next(uenum
, NULL
, &status
)) != NULL
&& U_SUCCESS(status
) ) {
2506 status
= U_ZERO_ERROR
;
2507 unumsys
= unumsys_openByName(numsys
, &status
);
2508 if ( U_SUCCESS(status
) ) {
2510 if ( uprv_strcmp(numsys
, "latn") ) foundLatn
= TRUE
;
2511 if ( uprv_strcmp(numsys
, "arab") ) foundArab
= TRUE
;
2512 unumsys_close(unumsys
);
2514 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2515 numsys
, myErrorName(status
));
2519 if ( numsysCount
< 40 || !foundLatn
|| !foundArab
) {
2520 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2521 numsysCount
, foundLatn
, foundArab
);
2524 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status
));
2528 /* plain-C version of test in numfmtst.cpp */
2529 enum { kUBufMax
= 64 };
2530 static void TestCurrencyIsoPluralFormat(void) {
2531 static const char* DATA
[][8] = {
2534 // currency amount to be formatted,
2535 // currency ISO code to be formatted,
2536 // format result using CURRENCYSTYLE,
2537 // format result using CURRENCY_STANDARD,
2538 // format result using CURRENCY_ACCOUNTING,
2539 // format result using ISOCURRENCYSTYLE,
2540 // format result using PLURALCURRENCYSTYLE,
2542 // locale amount ISOcode CURRENCYSTYLE CURRENCY_STANDARD CURRENCY_ACCOUNTING ISOCURRENCYSTYLE PLURALCURRENCYSTYLE
2543 {"en_US", "1", "USD", "$1.00", "$1.00", "$1.00", "USD1.00", "1.00 US dollars"},
2544 {"en_US", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
2545 {"en_US@cf=account", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
2546 {"en_US", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2547 {"en_US@cf=account", "-1234.56", "USD", "($1,234.56)", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2548 {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2549 {"zh_CN", "1", "USD", "US$1.00", "US$1.00", "US$1.00", "USD1.00", "1.00\\u7F8E\\u5143"},
2550 {"zh_CN", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2551 {"zh_CN@cf=account", "-1", "USD", "(US$1.00)", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2552 {"zh_CN@cf=standard", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2553 {"zh_CN", "1234.56", "USD", "US$1,234.56", "US$1,234.56", "US$1,234.56", "USD1,234.56", "1,234.56\\u7F8E\\u5143"},
2554 // {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "CHY1.00", "CHY1.00", "1.00 CHY"}, // wrong ISO code
2555 // {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, // wrong ISO code
2556 {"zh_CN", "1", "CNY", "\\u00A51.00", "\\u00A51.00", "\\u00A51.00", "CNY1.00", "1.00\\u4EBA\\u6C11\\u5E01"},
2557 {"zh_CN", "1234.56", "CNY", "\\u00A51,234.56", "\\u00A51,234.56", "\\u00A51,234.56", "CNY1,234.56", "1,234.56\\u4EBA\\u6C11\\u5E01"},
2558 {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2559 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2560 {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2561 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2562 {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2563 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2564 // test locale without currency information
2565 {"root", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2566 {"root@cf=account", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2567 // test choice format
2568 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
2570 static const UNumberFormatStyle currencyStyles
[] = {
2572 UNUM_CURRENCY_STANDARD
,
2573 UNUM_CURRENCY_ACCOUNTING
,
2575 UNUM_CURRENCY_PLURAL
2580 for (i
=0; i
<UPRV_LENGTHOF(DATA
); ++i
) {
2581 const char* localeString
= DATA
[i
][0];
2582 double numberToBeFormat
= atof(DATA
[i
][1]);
2583 const char* currencyISOCode
= DATA
[i
][2];
2584 for (sIndex
= 0; sIndex
< UPRV_LENGTHOF(currencyStyles
); ++sIndex
) {
2585 UNumberFormatStyle style
= currencyStyles
[sIndex
];
2586 UErrorCode status
= U_ZERO_ERROR
;
2587 UChar currencyCode
[4];
2588 UChar ubufResult
[kUBufMax
];
2589 UChar ubufExpected
[kUBufMax
];
2592 UNumberFormat
* unumFmt
= unum_open(style
, NULL
, 0, localeString
, NULL
, &status
);
2593 if (U_FAILURE(status
)) {
2594 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString
, (int)style
, myErrorName(status
));
2597 u_charsToUChars(currencyISOCode
, currencyCode
, 4);
2598 unum_setTextAttribute(unumFmt
, UNUM_CURRENCY_CODE
, currencyCode
, 3, &status
);
2599 if (U_FAILURE(status
)) {
2600 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s\n", localeString
, currencyISOCode
);
2602 ulenRes
= unum_formatDouble(unumFmt
, numberToBeFormat
, ubufResult
, kUBufMax
, NULL
, &status
);
2603 if (U_FAILURE(status
)) {
2604 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s - %s\n", localeString
, currencyISOCode
, myErrorName(status
));
2606 int32_t ulenExp
= u_unescape(DATA
[i
][3 + sIndex
], ubufExpected
, kUBufMax
);
2607 if (ulenRes
!= ulenExp
|| u_strncmp(ubufResult
, ubufExpected
, ulenExp
) != 0) {
2608 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got something else\n",
2609 localeString
, currencyISOCode
, DATA
[i
][3 + sIndex
]);
2612 unum_close(unumFmt
);
2618 const char * locale
;
2619 UNumberFormatStyle style
;
2620 UDisplayContext context
;
2621 const char * expectedResult
;
2624 /* currently no locales have contextTransforms data for "symbol" type */
2625 static const TestContextItem tcItems
[] = { /* results for 123.45 */
2626 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2627 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2628 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2629 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2630 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, "one hundred twenty-three point four five" },
2631 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
, "One hundred twenty-three point four five" },
2632 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
, "One hundred twenty-three point four five" },
2633 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, "One hundred twenty-three point four five" },
2634 { NULL
, (UNumberFormatStyle
)0, (UDisplayContext
)0, NULL
}
2637 static void TestContext(void) {
2638 UErrorCode status
= U_ZERO_ERROR
;
2639 const TestContextItem
* itemPtr
;
2641 UNumberFormat
*unum
= unum_open(UNUM_SPELLOUT
, NULL
, 0, "en", NULL
, &status
);
2642 if ( U_SUCCESS(status
) ) {
2643 UDisplayContext context
= unum_getContext(unum
, UDISPCTX_TYPE_CAPITALIZATION
, &status
);
2644 if ( U_FAILURE(status
) || context
!= UDISPCTX_CAPITALIZATION_NONE
) {
2645 log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n");
2646 status
= U_ZERO_ERROR
;
2648 unum_setContext(unum
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, &status
);
2649 context
= unum_getContext(unum
, UDISPCTX_TYPE_CAPITALIZATION
, &status
);
2650 if ( U_FAILURE(status
) || context
!= UDISPCTX_CAPITALIZATION_FOR_STANDALONE
) {
2651 log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n");
2655 log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status
));
2657 #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION
2658 for (itemPtr
= tcItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
2659 UChar ubufResult
[kUBufMax
];
2662 status
= U_ZERO_ERROR
;
2663 unum
= unum_open(itemPtr
->style
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
2664 if (U_FAILURE(status
)) {
2665 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2666 itemPtr
->locale
, (int)itemPtr
->style
, myErrorName(status
));
2669 unum_setContext(unum
, itemPtr
->context
, &status
);
2670 ulenRes
= unum_formatDouble(unum
, 123.45, ubufResult
, kUBufMax
, NULL
, &status
);
2671 if (U_FAILURE(status
)) {
2672 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
2673 itemPtr
->locale
, (int)itemPtr
->style
, (int)itemPtr
->context
, myErrorName(status
));
2675 UChar ubufExpected
[kUBufMax
];
2676 int32_t ulenExp
= u_unescape(itemPtr
->expectedResult
, ubufExpected
, kUBufMax
);
2677 if (ulenRes
!= ulenExp
|| u_strncmp(ubufResult
, ubufExpected
, ulenExp
) != 0) {
2678 char bbuf
[kUBufMax
*2];
2679 u_austrncpy(bbuf
, ubufResult
, sizeof(bbuf
));
2680 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
2681 itemPtr
->locale
, (int)itemPtr
->style
, (int)itemPtr
->context
, ulenExp
,
2682 itemPtr
->expectedResult
, ulenRes
, bbuf
);
2687 #endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */
2690 static void TestCurrencyUsage(void) {
2691 static const char* DATA
[][2] = {
2693 * currency ISO code to be formatted,
2694 * format result using CURRENCYSTYLE with CASH purpose,-
2695 * Note that as of CLDR 26:-
2696 * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
2697 * - CAD rounds to .05
2700 {"PKR", "PKR124"}, // ICU 61 behavior
2701 {"CAD", "CA$123.55"},
2705 // 1st time for getter/setter, 2nd for factory method
2708 const char* localeString
= "en_US";
2709 double numberToBeFormat
= 123.567;
2710 UNumberFormat
* unumFmt
;
2711 UNumberFormatStyle style
= UNUM_CURRENCY
;
2712 UErrorCode status
= U_ZERO_ERROR
;
2715 if(i
== 1){ // change for factory method
2716 style
= UNUM_CASH_CURRENCY
;
2719 unumFmt
= unum_open(style
, NULL
, 0, localeString
, NULL
, &status
);
2720 if (U_FAILURE(status
)) {
2721 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2722 localeString
, (int)style
, myErrorName(status
));
2726 if(i
== 0){ // this is for the getter/setter
2727 if(unum_getAttribute(unumFmt
, UNUM_CURRENCY_USAGE
) != UCURR_USAGE_STANDARD
) {
2728 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n");
2731 unum_setAttribute(unumFmt
, UNUM_CURRENCY_USAGE
, UCURR_USAGE_CASH
);
2734 if(unum_getAttribute(unumFmt
, UNUM_CURRENCY_USAGE
) != UCURR_USAGE_CASH
) {
2735 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n");
2738 for (j
=0; j
<UPRV_LENGTHOF(DATA
); ++j
) {
2741 UChar currencyCode
[4];
2744 UFieldPosition pos
= {0};
2746 u_charsToUChars(DATA
[j
][0], currencyCode
, 3);
2747 expectLen
= u_unescape(DATA
[j
][1], expect
, UPRV_LENGTHOF(expect
));
2749 unum_setTextAttribute(unumFmt
, UNUM_CURRENCY_CODE
, currencyCode
, 3, &status
);
2750 assertSuccess("num_setTextAttribute()", &status
);
2752 resultLen
= unum_formatDouble(unumFmt
, numberToBeFormat
, result
, UPRV_LENGTHOF(result
),
2754 assertSuccess("num_formatDouble()", &status
);
2756 if(resultLen
!= expectLen
|| u_strcmp(result
, expect
) != 0) {
2757 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n",
2758 aescstrdup(expect
, expectLen
), aescstrdup(result
, resultLen
));
2763 unum_close(unumFmt
);
2767 static UChar currFmtNegSameAsPos
[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */
2768 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2770 static UChar currFmtToPatExpected
[] = /* "\u00A4#,##0.00" */ // ICU 61 behavior
2771 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2773 static UChar currFmtResultExpected
[] = /* "$100.00" */
2774 {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0};
2776 static UChar emptyString
[] = {0};
2778 enum { kUBufSize
= 64, kBBufSize
= 128 };
2780 static void TestCurrFmtNegSameAsPositive(void) {
2781 UErrorCode status
= U_ZERO_ERROR
;
2782 UNumberFormat
* unumfmt
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
2783 if ( U_SUCCESS(status
) ) {
2784 unum_applyPattern(unumfmt
, FALSE
, currFmtNegSameAsPos
, -1, NULL
, &status
);
2785 if (U_SUCCESS(status
)) {
2786 UChar ubuf
[kUBufSize
];
2787 int32_t ulen
= unum_toPattern(unumfmt
, FALSE
, ubuf
, kUBufSize
, &status
);
2788 if (U_FAILURE(status
)) {
2789 log_err("unum_toPattern fails with status %s\n", myErrorName(status
));
2790 } else if (u_strcmp(ubuf
, currFmtToPatExpected
) != 0) {
2791 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected
,-1), aescstrdup(ubuf
,ulen
));
2793 unum_setSymbol(unumfmt
, UNUM_MINUS_SIGN_SYMBOL
, emptyString
, 0, &status
);
2794 if (U_SUCCESS(status
)) {
2795 ulen
= unum_formatDouble(unumfmt
, -100.0, ubuf
, kUBufSize
, NULL
, &status
);
2796 if (U_FAILURE(status
)) {
2797 log_err("unum_formatDouble fails with status %s\n", myErrorName(status
));
2798 } else if (u_strcmp(ubuf
, currFmtResultExpected
) != 0) {
2799 log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected
,-1), aescstrdup(ubuf
,ulen
));
2802 log_err("unum_setSymbol fails with status %s\n", myErrorName(status
));
2805 log_err("unum_applyPattern fails with status %s\n", myErrorName(status
));
2807 unum_close(unumfmt
);
2809 log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status
));
2816 const char *expected
;
2817 } ValueAndExpectedString
;
2819 static const ValueAndExpectedString enShort
[] = {
2826 {1234567.0, "1.23M"},
2827 {12345678.0, "12.3M"},
2828 {123456789.0, "123M"},
2829 {1.23456789E9
, "1.23B"},
2830 {1.23456789E10
, "12.3B"},
2831 {1.23456789E11
, "123B"},
2832 {1.23456789E12
, "1.23T"},
2833 {1.23456789E13
, "12.3T"},
2834 {1.23456789E14
, "123T"},
2835 {1.23456789E15
, "1230T"},
2839 static const ValueAndExpectedString enShortMax2
[] = {
2846 {1234567.0, "1.2M"},
2847 {12345678.0, "12M"},
2848 {123456789.0, "120M"},
2849 {1.23456789E9
, "1.2B"},
2850 {1.23456789E10
, "12B"},
2851 {1.23456789E11
, "120B"},
2852 {1.23456789E12
, "1.2T"},
2853 {1.23456789E13
, "12T"},
2854 {1.23456789E14
, "120T"},
2855 {1.23456789E15
, "1200T"},
2859 static const ValueAndExpectedString enShortMax5
[] = {
2864 {12345.0, "12.345K"},
2865 {123456.0, "123.46K"},
2866 {1234567.0, "1.2346M"},
2867 {12345678.0, "12.346M"},
2868 {123456789.0, "123.46M"},
2869 {1.23456789E9
, "1.2346B"},
2870 {1.23456789E10
, "12.346B"},
2871 {1.23456789E11
, "123.46B"},
2872 {1.23456789E12
, "1.2346T"},
2873 {1.23456789E13
, "12.346T"},
2874 {1.23456789E14
, "123.46T"},
2875 {1.23456789E15
, "1234.6T"},
2879 static const ValueAndExpectedString enShortMin3
[] = {
2886 {1234567.0, "1.23M"},
2887 {12345678.0, "12.3M"},
2888 {123456789.0, "123M"},
2889 {1.23456789E9
, "1.23B"},
2890 {1.23456789E10
, "12.3B"},
2891 {1.23456789E11
, "123B"},
2892 {1.23456789E12
, "1.23T"},
2893 {1.23456789E13
, "12.3T"},
2894 {1.23456789E14
, "123T"},
2895 {1.23456789E15
, "1230T"},
2899 static const ValueAndExpectedString jaShortMax2
[] = {
2901 {12345.0, "1.2\\u4E07"},
2902 {123456.0, "12\\u4E07"},
2903 {1234567.0, "120\\u4E07"},
2904 {12345678.0, "1200\\u4E07"},
2905 {123456789.0, "1.2\\u5104"},
2906 {1.23456789E9
, "12\\u5104"},
2907 {1.23456789E10
, "120\\u5104"},
2908 {1.23456789E11
, "1200\\u5104"},
2909 {1.23456789E12
, "1.2\\u5146"},
2910 {1.23456789E13
, "12\\u5146"},
2911 {1.23456789E14
, "120\\u5146"},
2915 static const ValueAndExpectedString srLongMax2
[] = {
2916 {1234.0, "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
2917 {12345.0, "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
2918 {21789.0, "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
2919 {123456.0, "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
2920 {999999.0, "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
2921 {1234567.0, "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
2922 {12345678.0, "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
2923 {123456789.0, "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
2924 {1.23456789E9
, "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
2925 {1.23456789E10
, "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
2926 {2.08901234E10
, "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
2927 {2.18901234E10
, "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
2928 {1.23456789E11
, "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
2929 {-1234.0, "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
2930 {-12345.0, "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
2931 {-21789.0, "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
2932 {-123456.0, "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
2933 {-999999.0, "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
2934 {-1234567.0, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2935 {-12345678.0, "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2936 {-123456789.0, "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2937 {-1.23456789E9
, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
2938 {-1.23456789E10
, "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
2939 {-2.08901234E10
, "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
2940 {-2.18901234E10
, "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
2941 {-1.23456789E11
, "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
2946 const char * locale
;
2947 UNumberFormatStyle style
;
2948 int32_t attribute
; // UNumberFormatAttribute, or -1 for none
2949 int32_t attrValue
; //
2950 const ValueAndExpectedString
* veItems
;
2951 } LocStyleAttributeTest
;
2953 static const LocStyleAttributeTest lsaTests
[] = {
2954 { "en", UNUM_DECIMAL_COMPACT_SHORT
, -1, 0, enShort
},
2955 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, enShortMax2
},
2956 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 5, enShortMax5
},
2957 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MIN_SIGNIFICANT_DIGITS
, 3, enShortMin3
},
2958 { "ja", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, jaShortMax2
},
2959 { "sr", UNUM_DECIMAL_COMPACT_LONG
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, srLongMax2
},
2960 { NULL
, (UNumberFormatStyle
)0, -1, 0, NULL
}
2963 static void TestVariousStylesAndAttributes(void) {
2964 const LocStyleAttributeTest
* lsaTestPtr
;
2965 for (lsaTestPtr
= lsaTests
; lsaTestPtr
->locale
!= NULL
; lsaTestPtr
++) {
2966 UErrorCode status
= U_ZERO_ERROR
;
2967 UNumberFormat
* unum
= unum_open(lsaTestPtr
->style
, NULL
, 0, lsaTestPtr
->locale
, NULL
, &status
);
2968 if ( U_FAILURE(status
) ) {
2969 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, u_errorName(status
));
2971 const ValueAndExpectedString
* veItemPtr
;
2972 if (lsaTestPtr
->attribute
>= 0) {
2973 unum_setAttribute(unum
, (UNumberFormatAttribute
)lsaTestPtr
->attribute
, lsaTestPtr
->attrValue
);
2975 // ICU 62: should call minSignificantDigits in tandem with maxSignificantDigits.
2976 if (lsaTestPtr
->attribute
== UNUM_MIN_SIGNIFICANT_DIGITS
) {
2977 unum_setAttribute(unum
, UNUM_MAX_SIGNIFICANT_DIGITS
, lsaTestPtr
->attrValue
);
2979 for (veItemPtr
= lsaTestPtr
->veItems
; veItemPtr
->expected
!= NULL
; veItemPtr
++) {
2980 UChar uexp
[kUBufSize
];
2981 UChar uget
[kUBufSize
];
2982 int32_t uexplen
, ugetlen
;
2984 status
= U_ZERO_ERROR
;
2985 uexplen
= u_unescape(veItemPtr
->expected
, uexp
, kUBufSize
);
2986 ugetlen
= unum_formatDouble(unum
, veItemPtr
->value
, uget
, kUBufSize
, NULL
, &status
);
2987 if ( U_FAILURE(status
) ) {
2988 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n",
2989 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->value
, u_errorName(status
));
2990 } else if (ugetlen
!= uexplen
|| u_strncmp(uget
, uexp
, uexplen
) != 0) {
2991 char bexp
[kBBufSize
];
2992 char bget
[kBBufSize
];
2993 u_strToUTF8(bexp
, kBBufSize
, NULL
, uexp
, uexplen
, &status
);
2994 u_strToUTF8(bget
, kBBufSize
, NULL
, uget
, ugetlen
, &status
);
2995 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n",
2996 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->value
, bexp
, bget
);
3004 static const UChar currpat
[] = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; /* ¤#,##0.00 */
3005 static const UChar parsetxt
[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */
3007 static void TestParseCurrPatternWithDecStyle() {
3008 UErrorCode status
= U_ZERO_ERROR
;
3009 UNumberFormat
*unumfmt
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
3010 if (U_FAILURE(status
)) {
3011 log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status
));
3013 unum_applyPattern(unumfmt
, FALSE
, currpat
, -1, NULL
, &status
);
3014 if (U_FAILURE(status
)) {
3015 log_err_status(status
, "unum_applyPattern failed: %s\n", u_errorName(status
));
3018 double value
= unum_parseDouble(unumfmt
, parsetxt
, -1, &pos
, &status
);
3019 if (U_SUCCESS(status
)) {
3020 log_err_status(status
, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status
), value
);
3023 unum_close(unumfmt
);
3029 * Test unum_formatDoubleForFields (and UFieldPositionIterator)
3039 const char * locale
;
3040 UNumberFormatStyle style
;
3042 const FieldsData
* expectedFields
;
3043 } FormatForFieldsItem
;
3045 static const UChar patNoFields
[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
3048 /* "en_US", UNUM_CURRENCY, 123456.0 : "¤#,##0.00" => "$123,456.00" */
3049 static const FieldsData fields_en_CURR
[] = {
3050 { UNUM_CURRENCY_FIELD
/*7*/, 0, 1 },
3051 { UNUM_GROUPING_SEPARATOR_FIELD
/*6*/, 4, 5 },
3052 { UNUM_INTEGER_FIELD
/*0*/, 1, 8 },
3053 { UNUM_DECIMAL_SEPARATOR_FIELD
/*2*/, 8, 9 },
3054 { UNUM_FRACTION_FIELD
/*1*/, 9, 11 },
3057 /* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
3058 static const FieldsData fields_en_PRCT
[] = {
3059 { UNUM_SIGN_FIELD
/*10*/, 0, 1 },
3060 { UNUM_INTEGER_FIELD
/*0*/, 1, 3 },
3061 { UNUM_PERCENT_FIELD
/*8*/, 3, 4 },
3064 /* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00 ¤" => "123,456.00 €" */
3065 static const FieldsData fields_fr_CURR
[] = {
3066 { UNUM_GROUPING_SEPARATOR_FIELD
/*6*/, 3, 4 },
3067 { UNUM_INTEGER_FIELD
/*0*/, 0, 7 },
3068 { UNUM_DECIMAL_SEPARATOR_FIELD
/*2*/, 7, 8 },
3069 { UNUM_FRACTION_FIELD
/*1*/, 8, 10 },
3070 { UNUM_CURRENCY_FIELD
/*7*/, 11, 12 },
3073 /* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
3074 static const FieldsData fields_en_PATN
[] = {
3075 { UNUM_INTEGER_FIELD
/*0*/, 1, 3 },
3079 static const FormatForFieldsItem fffItems
[] = {
3080 { "en_US", UNUM_CURRENCY_STANDARD
, 123456.0, fields_en_CURR
},
3081 { "en_US", UNUM_PERCENT
, -0.34, fields_en_PRCT
},
3082 { "fr_FR", UNUM_CURRENCY_STANDARD
, 123456.0, fields_fr_CURR
},
3083 { "en_US", UNUM_PATTERN_DECIMAL
, 12.0, fields_en_PATN
},
3084 { NULL
, (UNumberFormatStyle
)0, 0, NULL
},
3087 static void TestFormatForFields(void) {
3088 UErrorCode status
= U_ZERO_ERROR
;
3089 UFieldPositionIterator
* fpositer
= ufieldpositer_open(&status
);
3090 if ( U_FAILURE(status
) ) {
3091 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status
));
3093 const FormatForFieldsItem
* itemPtr
;
3094 for (itemPtr
= fffItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3095 UNumberFormat
* unum
;
3096 status
= U_ZERO_ERROR
;
3097 unum
= (itemPtr
->style
== UNUM_PATTERN_DECIMAL
)?
3098 unum_open(itemPtr
->style
, patNoFields
, -1, itemPtr
->locale
, NULL
, &status
):
3099 unum_open(itemPtr
->style
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3100 if ( U_FAILURE(status
) ) {
3101 log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr
->locale
, itemPtr
->style
, u_errorName(status
));
3103 UChar ubuf
[kUBufSize
];
3104 int32_t ulen
= unum_formatDoubleForFields(unum
, itemPtr
->value
, ubuf
, kUBufSize
, fpositer
, &status
);
3105 if ( U_FAILURE(status
) ) {
3106 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr
->locale
, itemPtr
->style
, u_errorName(status
));
3108 const FieldsData
* fptr
;
3109 int32_t field
, beginPos
, endPos
;
3110 for (fptr
= itemPtr
->expectedFields
; TRUE
; fptr
++) {
3111 field
= ufieldpositer_next(fpositer
, &beginPos
, &endPos
);
3112 if (field
!= fptr
->field
|| (field
>= 0 && (beginPos
!= fptr
->beginPos
|| endPos
!= fptr
->endPos
))) {
3113 if (fptr
->field
>= 0) {
3114 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
3115 itemPtr
->locale
, aescstrdup(ubuf
, ulen
), fptr
->field
, fptr
->beginPos
, fptr
->endPos
, field
, beginPos
, endPos
);
3117 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
3118 itemPtr
->locale
, aescstrdup(ubuf
, ulen
), field
, beginPos
, endPos
);
3130 ufieldpositer_close(fpositer
);
3134 static void Test12052_NullPointer() {
3135 UErrorCode status
= U_ZERO_ERROR
;
3136 static const UChar input
[] = u
"199a";
3137 UChar currency
[200] = {0};
3138 UNumberFormat
*theFormatter
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
3139 if (!assertSuccessCheck("unum_open() failed", &status
, TRUE
)) { return; }
3140 status
= U_ZERO_ERROR
;
3141 unum_setAttribute(theFormatter
, UNUM_LENIENT_PARSE
, 1);
3143 unum_parseDoubleCurrency(theFormatter
, input
, -1, &pos
, currency
, &status
);
3144 assertEquals("should fail gracefully", "U_PARSE_ERROR", u_errorName(status
));
3145 unum_close(theFormatter
);
3150 const UChar
* text
; // text to parse
3151 UBool lenient
; // leniency to use
3152 UErrorCode intStatus
; // expected status from parse
3153 int32_t intPos
; // expected final pos from parse
3154 int32_t intValue
; // expected value from parse
3155 UErrorCode doubStatus
; // expected status from parseDouble
3156 int32_t doubPos
; // expected final pos from parseDouble
3157 double doubValue
; // expected value from parseDouble
3160 static const ParseCaseItem parseCaseItems
[] = {
3161 { "en", u
"0,000", FALSE
, U_ZERO_ERROR
, 5, 0, U_ZERO_ERROR
, 5, 0.0 },
3162 { "en", u
"0,000", TRUE
, U_ZERO_ERROR
, 5, 0, U_ZERO_ERROR
, 5, 0.0 },
3163 { "en", u
",024", FALSE
, U_ZERO_ERROR
, 4, 24, U_ZERO_ERROR
, 4, 24.0 },
3164 { "en", u
",024", TRUE
, U_ZERO_ERROR
, 4, 24, U_ZERO_ERROR
, 4, 24.0 },
3165 { "en", u
"1000,000", FALSE
, U_ZERO_ERROR
, 8, 1000000, U_ZERO_ERROR
, 8, 1000000.0 },
3166 { "en", u
"1000,000", TRUE
, U_ZERO_ERROR
, 8, 1000000, U_ZERO_ERROR
, 8, 1000000.0 },
3167 { NULL
, NULL
, 0, 0, 0, 0, 0, 0, 0.0 }
3170 // Currently Apple only
3171 static void TestParseCases(void) {
3172 const ParseCaseItem
* itemPtr
;
3173 for (itemPtr
= parseCaseItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3174 UErrorCode status
= U_ZERO_ERROR
;
3175 UNumberFormat
* unumDec
= unum_open(UNUM_DECIMAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3176 if (U_FAILURE(status
)) {
3177 log_data_err("unum_open UNUM_DECIMAL fails for locale %s: %s\n", itemPtr
->locale
, u_errorName(status
));
3180 int32_t intValue
, parsePos
;
3182 unum_setAttribute(unumDec
, UNUM_LENIENT_PARSE
, itemPtr
->lenient
);
3185 status
= U_ZERO_ERROR
;
3186 intValue
= unum_parse(unumDec
, itemPtr
->text
, -1, &parsePos
, &status
);
3187 if (status
!= itemPtr
->intStatus
|| parsePos
!= itemPtr
->intPos
|| intValue
!= itemPtr
->intValue
) {
3189 u_austrcpy(btext
, itemPtr
->text
);
3190 log_err("locale %s, text \"%s\", lenient %d;\n parse expected status %s, pos %d, value %d;\n got %s, %d, %d\n",
3191 itemPtr
->locale
, btext
, itemPtr
->lenient
, u_errorName(itemPtr
->intStatus
), itemPtr
->intPos
, itemPtr
->intValue
,
3192 u_errorName(status
), parsePos
, intValue
);
3196 status
= U_ZERO_ERROR
;
3197 doubValue
= unum_parseDouble(unumDec
, itemPtr
->text
, -1, &parsePos
, &status
);
3198 if (status
!= itemPtr
->doubStatus
|| parsePos
!= itemPtr
->doubPos
|| doubValue
!= itemPtr
->doubValue
) {
3200 u_austrcpy(btext
, itemPtr
->text
);
3201 log_err("locale %s, text \"%s\", lenient %d;\n parseDouble expected status %s, pos %d, value %.1f;\n got %s, %d, %.1f\n",
3202 itemPtr
->locale
, btext
, itemPtr
->lenient
, u_errorName(itemPtr
->doubStatus
), itemPtr
->doubPos
, itemPtr
->doubValue
,
3203 u_errorName(status
), parsePos
, doubValue
);
3211 const UChar
* formatLimitPrecision
;
3212 const UChar
* formatFullPrecision
;
3213 } FormatPrecisionItem
;
3215 static const FormatPrecisionItem formatPrecisionItems
[] = {
3216 { "en_US", 0.33333333 - 0.00333333, u
"0.33", u
"0.32999999999999996" },
3217 { "en_US", 0.07 * 100.0, u
"7", u
"7.000000000000001" },
3218 { NULL
, 0.0, NULL
, NULL
}
3221 static const UChar
* patternTestPrecision
= u
"#0.################################################################################"; // 80 fraction places
3223 // Currently Apple only
3224 static void TestFormatPrecision(void) {
3225 const FormatPrecisionItem
* itemPtr
;
3226 for (itemPtr
= formatPrecisionItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3227 UErrorCode status
= U_ZERO_ERROR
;
3229 UNumberFormat
*unum
= unum_open(UNUM_PATTERN_DECIMAL
, patternTestPrecision
, -1, itemPtr
->locale
, &perr
, &status
);
3230 if (U_FAILURE(status
)) {
3231 log_data_err("unum_open UNUM_PATTERN_DECIMAL fails for locale %s: %s\n", itemPtr
->locale
, u_errorName(status
));
3234 UChar ubuf
[kUBufSize
];
3236 UFieldPosition fpos
;
3237 UBool formatFullPrecision
;
3239 formatFullPrecision
= (UBool
)unum_getAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
);
3240 if (formatFullPrecision
) {
3241 log_err("unum_getAttribute, default for UNUM_FORMAT_WITH_FULL_PRECISION is not FALSE\n");
3243 status
= U_ZERO_ERROR
;
3244 ulen
= unum_formatDouble(unum
, itemPtr
->value
, ubuf
, kUBufSize
, &fpos
, &status
);
3245 if (U_FAILURE(status
)) {
3246 log_err("unum_formatDouble locale %s val %.20f limit precision fails with %s\n", itemPtr
->locale
, itemPtr
->value
, u_errorName(status
));
3247 } else if (ulen
!= u_strlen(itemPtr
->formatLimitPrecision
) || u_strcmp(ubuf
, itemPtr
->formatLimitPrecision
) != 0) {
3248 char bbufe
[kBBufSize
];
3249 char bbufg
[kBBufSize
];
3250 u_strToUTF8(bbufe
, kBBufSize
, NULL
, itemPtr
->formatLimitPrecision
, -1, &status
);
3251 u_strToUTF8(bbufg
, kBBufSize
, NULL
, ubuf
, ulen
, &status
);
3252 log_err("unum_formatDouble locale %s val %.20f limit precision, expect %s, get %s\n", itemPtr
->locale
, itemPtr
->value
, bbufe
, bbufg
);
3256 unum_setAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
, TRUE
);
3257 formatFullPrecision
= (UBool
)unum_getAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
);
3258 if (!formatFullPrecision
) {
3259 log_err("unum_getAttribute, after set UNUM_FORMAT_WITH_FULL_PRECISION is not TRUE\n");
3261 status
= U_ZERO_ERROR
;
3262 ulen
= unum_formatDouble(unum
, itemPtr
->value
, ubuf
, kUBufSize
, &fpos
, &status
);
3263 if (U_FAILURE(status
)) {
3264 log_err("unum_formatDouble locale %s val %.20f full precision fails with %s\n", itemPtr
->locale
, itemPtr
->value
, u_errorName(status
));
3265 } else if (ulen
!= u_strlen(itemPtr
->formatFullPrecision
) || u_strcmp(ubuf
, itemPtr
->formatFullPrecision
) != 0) {
3266 char bbufe
[kBBufSize
];
3267 char bbufg
[kBBufSize
];
3268 u_strToUTF8(bbufe
, kBBufSize
, NULL
, itemPtr
->formatFullPrecision
, -1, &status
);
3269 u_strToUTF8(bbufg
, kBBufSize
, NULL
, ubuf
, ulen
, &status
);
3270 log_err("unum_formatDouble locale %s val %.20f full precision, expect %s, get %s\n", itemPtr
->locale
, itemPtr
->value
, bbufe
, bbufg
);
3278 // Currently Apple only for <rdar://problem/49159521>
3279 enum { kBBufMax
= 128 };
3280 static const UChar
* pat1
= u
"#.##E+00;-#.##E+00";
3281 static void TestSciNotationRound(void) {
3282 UErrorCode status
= U_ZERO_ERROR
;
3283 UNumberFormat
* unum
= unum_open(UNUM_PATTERN_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
3284 if ( U_FAILURE(status
) ) {
3285 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status
));
3287 unum_applyPattern(unum
, FALSE
, pat1
, u_strlen(pat1
), NULL
, &status
);
3288 if ( U_FAILURE(status
) ) {
3289 log_err("unum_applyPattern fails with %s\n", u_errorName(status
));
3292 UChar ubuf
[kUBufMax
];
3293 char bbuf
[kBBufMax
];
3296 unum_setAttribute(unum
, UNUM_ROUNDING_MODE
, UNUM_ROUND_HALFUP
);
3297 unum_setAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
, 0);
3298 unum_setAttribute(unum
, UNUM_MAX_FRACTION_DIGITS
, 50); // problem happens at 15 or more
3300 for (value
= 10000000000000000000000.0; value
< 1000000000000000000000000000000000000000.0; value
*= 10.0) {
3301 status
= U_ZERO_ERROR
;
3302 ulen
= unum_formatDouble(unum
, value
, ubuf
, kUBufMax
, NULL
, &status
);
3303 if ( U_FAILURE(status
) ) {
3304 printf("unum_formatDouble value %.1f status %s\n", value
, u_errorName(status
));
3305 } else if (u_strncmp(ubuf
,u
"1E+",3) != 0) {
3306 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3307 log_err("unum_formatDouble value %.1f expected result to begin with 1E+, got %s\n", value
, bbuf
);
3315 #endif /* #if !UCONFIG_NO_FORMATTING */