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"
34 #include "unicode/uchar.h"
45 #define APPLE_ADDITIONS 1
47 static const char *tagAssert(const char *f
, int32_t l
, const char *msg
) {
48 static char _fileline
[1000];
49 sprintf(_fileline
, "%s:%d: ASSERT_TRUE(%s)", f
, l
, msg
);
53 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
55 void addNumForTest(TestNode
** root
);
56 static void TestTextAttributeCrash(void);
57 static void TestNBSPInPattern(void);
58 static void TestInt64Parse(void);
59 static void TestParseCurrency(void);
60 static void TestMaxInt(void);
61 static void TestNoExponent(void);
62 static void TestSignAlwaysShown(void);
63 static void TestMinimumGroupingDigits(void);
64 static void TestParseCaseSensitive(void);
65 static void TestUFormattable(void);
66 static void TestUNumberingSystem(void);
67 static void TestCurrencyIsoPluralFormat(void);
68 static void TestContext(void);
69 static void TestCurrencyUsage(void);
70 static void TestCurrFmtNegSameAsPositive(void);
71 static void TestVariousStylesAndAttributes(void);
72 static void TestParseCurrPatternWithDecStyle(void);
73 static void TestFormatForFields(void);
74 static void TestRBNFRounding(void);
75 static void Test12052_NullPointer(void);
76 static void TestParseCases(void);
77 static void TestSetMaxFracAndRoundIncr(void);
78 static void TestIgnorePadding(void);
79 static void TestParseAltNum(void);
80 static void TestParseCurrPatternWithDecStyle(void);
81 static void TestFormatPrecision(void);
82 static void TestSetSigDigAndRoundIncr(void); // Apple <rdar://problem/52538227>
83 static void TestSetAffixOnCurrFmt(void); // Apple <rdar://problem/46755430>
84 static void TestParseWithEmptyCurr(void); // Apple <rdar://problem/46915356>
85 static void TestSciNotationNumbers(void); // Apple <rdar://problem/50113359>
86 static void TestSciNotationPrecision(void); // Apple <rdar://problem/51601250>
87 static void TestMinimumGrouping(void); // Apple <rdar://problem/49808819>
88 static void TestNumberSystemsMultiplier(void); // Apple <rdar://problem/49120648>
89 static void TestParseScientific(void); // Apple <rdar://problem/39156484>
90 static void TestCurrForUnkRegion(void); // Apple <rdar://problem/51985640>
91 static void TestMinIntMinFracZero(void); // Apple <rdar://problem/54569257>
93 static void TestFormatDecPerf(void); // Apple <rdar://problem/51672521>
96 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
98 void addNumForTest(TestNode
** root
)
100 TESTCASE(TestNumberFormat
);
101 TESTCASE(TestSpelloutNumberParse
);
102 TESTCASE(TestSignificantDigits
);
103 TESTCASE(TestSigDigRounding
);
104 TESTCASE(TestNumberFormatPadding
);
105 TESTCASE(TestInt64Format
);
106 TESTCASE(TestNonExistentCurrency
);
107 TESTCASE(TestCurrencyRegression
);
108 TESTCASE(TestTextAttributeCrash
);
109 TESTCASE(TestRBNFFormat
);
110 TESTCASE(TestRBNFRounding
);
111 TESTCASE(TestNBSPInPattern
);
112 TESTCASE(TestInt64Parse
);
113 TESTCASE(TestParseZero
);
114 TESTCASE(TestParseCurrency
);
115 TESTCASE(TestCloneWithRBNF
);
116 TESTCASE(TestMaxInt
);
117 TESTCASE(TestNoExponent
);
118 TESTCASE(TestSignAlwaysShown
);
119 TESTCASE(TestMinimumGroupingDigits
);
120 TESTCASE(TestParseCaseSensitive
);
121 TESTCASE(TestUFormattable
);
122 TESTCASE(TestUNumberingSystem
);
123 TESTCASE(TestCurrencyIsoPluralFormat
);
124 TESTCASE(TestContext
);
125 TESTCASE(TestCurrencyUsage
);
126 TESTCASE(TestCurrFmtNegSameAsPositive
);
127 TESTCASE(TestVariousStylesAndAttributes
);
128 TESTCASE(TestParseCurrPatternWithDecStyle
);
129 TESTCASE(TestFormatForFields
);
130 TESTCASE(Test12052_NullPointer
);
131 TESTCASE(TestParseCases
);
132 TESTCASE(TestSetMaxFracAndRoundIncr
);
133 TESTCASE(TestIgnorePadding
);
134 TESTCASE(TestParseAltNum
);
135 TESTCASE(TestParseCurrPatternWithDecStyle
);
136 TESTCASE(TestFormatPrecision
);
137 TESTCASE(TestSetSigDigAndRoundIncr
); // Apple <rdar://problem/52538227>
138 TESTCASE(TestSetAffixOnCurrFmt
); // Apple <rdar://problem/46755430>
139 TESTCASE(TestParseWithEmptyCurr
); // Apple <rdar://problem/46915356>
140 TESTCASE(TestSciNotationNumbers
); // Apple <rdar://problem/50113359>
141 TESTCASE(TestSciNotationPrecision
); // Apple <rdar://problem/51601250>
142 TESTCASE(TestMinimumGrouping
); // Apple <rdar://problem/49808819>
143 TESTCASE(TestNumberSystemsMultiplier
); // Apple <rdar://problem/49120648>
144 TESTCASE(TestParseScientific
); // Apple <rdar://problem/39156484>
145 TESTCASE(TestCurrForUnkRegion
); // Apple <rdar://problem/51985640>
146 TESTCASE(TestMinIntMinFracZero
); // Apple <rdar://problem/54569257>
148 TESTCASE(TestFormatDecPerf
); // Apple <rdar://problem/51672521>
152 /* test Parse int 64 */
154 static void TestInt64Parse()
157 UErrorCode st
= U_ZERO_ERROR
;
158 UErrorCode
* status
= &st
;
160 const char* st1
= "009223372036854775808";
169 u_charsToUChars(st1
, text
, size
);
170 nf
= unum_open(UNUM_DEFAULT
, NULL
, -1, NULL
, NULL
, status
);
172 if(U_FAILURE(*status
))
174 log_data_err("Error in unum_open() %s \n", myErrorName(*status
));
178 log_verbose("About to test unum_parseInt64() with out of range number\n");
180 a
= unum_parseInt64(nf
, text
, size
, 0, status
);
181 (void)a
; /* Suppress set but not used warning. */
184 if(!U_FAILURE(*status
))
186 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status
));
190 log_verbose("unum_parseInt64() successful\n");
197 /* test Number Format API */
198 static void TestNumberFormat()
209 int32_t resultlength
;
210 int32_t resultlengthneeded
;
214 double d
= -10456.37;
215 double a
= 1234.56, a1
= 1235.0;
216 int32_t l
= 100000000;
222 UNumberFormatAttribute attr
;
223 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
225 UErrorCode status
=U_ZERO_ERROR
;
226 UNumberFormatStyle style
= UNUM_DEFAULT
;
227 UNumberFormat
*pattern
;
228 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
229 *cur_frpattern
, *myclone
, *spellout_def
;
231 /* Testing unum_open() with various Numberformat styles and locales*/
232 status
= U_ZERO_ERROR
;
233 log_verbose("Testing unum_open() with default style and locale\n");
234 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
236 /* Might as well pack it in now if we can't even get a default NumberFormat... */
237 if(U_FAILURE(status
))
239 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status
));
243 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
244 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
245 if(U_FAILURE(status
))
246 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
248 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
250 /* Can't hardcode the result to assume the default locale is "en_US". */
251 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
252 if(U_FAILURE(status
))
253 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
254 myErrorName(status
) );
256 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
257 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
258 if(U_FAILURE(status
))
259 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
260 myErrorName(status
));
262 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
264 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
265 if(U_FAILURE(status
))
266 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
268 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
269 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
270 if(U_FAILURE(status
))
271 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
273 log_verbose("\nTesting unum_open(spellout, NULL, status)");
275 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
276 if(U_FAILURE(status
))
277 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
279 /* Testing unum_clone(..) */
280 log_verbose("\nTesting unum_clone(fmt, status)");
281 status
= U_ZERO_ERROR
;
282 myclone
= unum_clone(def
,&status
);
283 if(U_FAILURE(status
))
284 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
287 log_verbose("unum_clone() successful\n");
290 /*Testing unum_getAvailable() and unum_countAvailable()*/
291 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
292 numlocales
=unum_countAvailable();
294 log_err("error in countAvailable");
296 log_verbose("unum_countAvialable() successful\n");
297 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
299 for(i
=0;i
<numlocales
;i
++)
301 log_verbose("%s\n", unum_getAvailable(i
));
302 if (unum_getAvailable(i
) == 0)
303 log_err("No locale for which number formatting patterns are applicable\n");
305 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
309 /*Testing unum_format() and unum_formatdouble()*/
310 u_uastrcpy(temp1
, "$100,000,000.00");
312 log_verbose("\nTesting unum_format() \n");
314 pos1
.field
= UNUM_INTEGER_FIELD
;
315 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
316 if(status
==U_BUFFER_OVERFLOW_ERROR
)
319 resultlength
=resultlengthneeded
+1;
320 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
321 /* for (i = 0; i < 100000; i++) */
323 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
327 if(U_FAILURE(status
))
329 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
331 if(u_strcmp(result
, temp1
)==0)
332 log_verbose("Pass: Number formatting using unum_format() successful\n");
334 log_err("Fail: Error in number Formatting using unum_format()\n");
335 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
336 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
338 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
339 pos1
.beginIndex
, pos1
.endIndex
);
344 log_verbose("\nTesting unum_formatDouble()\n");
345 u_uastrcpy(temp1
, "-$10,456.37");
347 pos2
.field
= UNUM_FRACTION_FIELD
;
348 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
349 if(status
==U_BUFFER_OVERFLOW_ERROR
)
352 resultlength
=resultlengthneeded
+1;
353 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
354 /* for (i = 0; i < 100000; i++) */
356 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
359 if(U_FAILURE(status
))
361 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
363 if(result
&& u_strcmp(result
, temp1
)==0)
364 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
366 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
367 aescstrdup(result
, -1), aescstrdup(temp1
, -1));
369 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
370 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
372 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
373 pos1
.beginIndex
, pos1
.endIndex
);
376 /* Testing unum_parse() and unum_parseDouble() */
377 log_verbose("\nTesting unum_parseDouble()\n");
378 /* for (i = 0; i < 100000; i++)*/
380 if (result
!= NULL
) {
381 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
383 log_err("result is NULL\n");
385 if(U_FAILURE(status
)) {
386 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result
,u_strlen(result
)),parsepos
, myErrorName(status
));
390 log_err("Fail: Error in parsing\n");
392 log_verbose("Pass: parsing successful\n");
397 status
= U_ZERO_ERROR
;
398 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
399 log_verbose("\nTesting unum_formatDoubleCurrency\n");
400 u_uastrcpy(temp1
, "Y1,235");
401 temp1
[0] = 0xA5; /* Yen sign */
402 u_uastrcpy(temp
, "JPY");
404 pos2
.field
= UNUM_INTEGER_FIELD
;
405 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
406 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
408 resultlength
=resultlengthneeded
+1;
409 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
410 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
412 if (U_FAILURE(status
)) {
413 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status
));
415 if (result
&& u_strcmp(result
, temp1
)==0) {
416 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
418 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
419 aescstrdup(result
, -1), aescstrdup(temp1
, -1));
421 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
422 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
424 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
425 pos1
.beginIndex
, pos1
.endIndex
);
428 log_verbose("\nTesting unum_parseDoubleCurrency\n");
430 if (result
== NULL
) {
431 log_err("result is NULL\n");
434 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
435 if (U_FAILURE(status
)) {
436 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result
, u_strlen(result
)), myErrorName(status
));
438 /* Note: a==1234.56, but on parse expect a1=1235.0 */
440 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
442 log_verbose("Pass: parsed currency amount successfully\n");
444 if (u_strcmp(temp2
, temp
)==0) {
445 log_verbose("Pass: parsed correct currency\n");
447 log_err("Fail: parsed incorrect currency\n");
450 status
= U_ZERO_ERROR
; /* reset */
456 /* performance testing */
457 u_uastrcpy(temp1
, "$462.12345");
458 resultlength
=u_strlen(temp1
);
459 /* for (i = 0; i < 100000; i++) */
462 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
464 if(U_FAILURE(status
))
466 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1
, resultlength
), myErrorName(status
));
470 * Note: "for strict standard conformance all operations and constants are now supposed to be
471 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
476 log_err("Fail: Error in parsing\n");
478 log_verbose("Pass: parsing successful\n");
482 u_uastrcpy(temp1
, "($10,456.3E1])");
484 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
485 if(U_SUCCESS(status
))
487 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
491 log_verbose("\nTesting unum_format()\n");
495 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
496 if(status
==U_BUFFER_OVERFLOW_ERROR
)
499 resultlength
=resultlengthneeded
+1;
500 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
501 /* for (i = 0; i < 100000; i++)*/
503 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
506 if(U_FAILURE(status
))
508 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
512 log_verbose("\nTesting unum_parse()\n");
513 /* for (i = 0; i < 100000; i++) */
516 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
518 if(U_FAILURE(status
))
520 log_err("parse failed. The error is : %s\n", myErrorName(status
));
524 log_err("Fail: Error in parsing\n");
526 log_verbose("Pass: parsing successful\n");
530 /* create a number format using unum_openPattern(....)*/
531 log_verbose("\nTesting unum_openPattern()\n");
532 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
533 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
534 if(U_FAILURE(status
))
536 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
539 log_verbose("Pass: unum_openPattern() works fine\n");
541 /*test for unum_toPattern()*/
542 log_verbose("\nTesting unum_toPattern()\n");
544 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
545 if(status
==U_BUFFER_OVERFLOW_ERROR
)
548 resultlength
=resultlengthneeded
+1;
549 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
550 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
552 if(U_FAILURE(status
))
554 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
558 if(u_strcmp(result
, temp1
)!=0)
559 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
561 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
565 /*Testing unum_getSymbols() and unum_setSymbols()*/
566 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
567 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
569 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
570 if(status
==U_BUFFER_OVERFLOW_ERROR
)
573 resultlength
=resultlengthneeded
+1;
574 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
575 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
577 if(U_FAILURE(status
))
579 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
583 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
584 if(U_FAILURE(status
))
586 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
591 /*getting the symbols of cur_def */
592 /*set the symbols of cur_frpattern to cur_def */
593 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
595 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
596 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
597 if(U_FAILURE(status
))
599 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
603 /*format to check the result */
605 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
606 if(status
==U_BUFFER_OVERFLOW_ERROR
)
609 resultlength
=resultlengthneeded
+1;
610 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
611 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
613 if(U_FAILURE(status
))
615 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
618 if(U_FAILURE(status
)){
619 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
621 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
623 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
625 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
626 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
627 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
629 log_err("Fail: error in getting symbols\n");
632 log_verbose("Pass: get and set symbols successful\n");
635 /*format and check with the previous result */
638 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
639 if(status
==U_BUFFER_OVERFLOW_ERROR
)
642 resultlength
=resultlengthneeded
+1;
643 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
645 if(U_FAILURE(status
))
647 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
650 * This test fails because we have not called unum_applyPattern().
651 * Currently, such an applyPattern() does not exist on the C API, and
652 * we have jitterbug 411 for it.
653 * Since it is close to the 1.5 release, I (markus) am disabling this test just
654 * for this release (I added the test itself only last week).
655 * For the next release, we need to fix this.
656 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
658 if(u_strcmp(result
, temp1
) != 0) {
659 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
667 /* Testing unum_get/setSymbol() */
668 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
669 symbol
[0] = (UChar
)(0x41 + i
);
670 symbol
[1] = (UChar
)(0x61 + i
);
671 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
672 if(U_FAILURE(status
)) {
673 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
677 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
678 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, UPRV_LENGTHOF(symbol
), &status
);
679 if(U_FAILURE(status
)) {
680 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
683 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
684 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
687 /*try getting from a bogus symbol*/
688 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, UPRV_LENGTHOF(symbol
), &status
);
689 if(U_SUCCESS(status
)){
690 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
692 if(U_FAILURE(status
)){
693 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
694 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
699 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
700 log_verbose("\nTesting getting and setting text attributes\n");
702 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
703 if(U_FAILURE(status
))
705 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
707 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
708 if(U_FAILURE(status
))
710 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
712 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
713 if(U_FAILURE(status
))
715 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
717 if(u_strcmp(suffix
,temp
)!=0)
718 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
720 log_verbose("Pass: setting and getting suffix works fine\n");
721 /*set it back to normal */
722 u_uastrcpy(temp
,"$");
723 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
725 /*checking some more text setter conditions */
726 u_uastrcpy(prefix
, "+");
727 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
728 if(U_FAILURE(status
))
730 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
732 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
733 if(U_FAILURE(status
))
735 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
738 if(u_strcmp(prefix
, temp
)!=0)
739 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
741 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
743 u_uastrcpy(prefix
, "+");
744 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
745 if(U_FAILURE(status
))
747 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
749 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
750 if(U_FAILURE(status
))
752 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
754 if(u_strcmp(prefix
, temp
)!=0)
755 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
757 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
759 u_uastrcpy(suffix
, "+");
760 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
761 if(U_FAILURE(status
))
763 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
766 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
767 if(U_FAILURE(status
))
769 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
771 if(u_strcmp(suffix
, temp
)!=0)
772 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
774 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
776 u_uastrcpy(suffix
, "++");
777 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
778 if(U_FAILURE(status
))
780 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
783 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
784 if(U_FAILURE(status
))
786 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
788 if(u_strcmp(suffix
, temp
)!=0)
789 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
791 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
793 /*Testing unum_getAttribute and unum_setAttribute() */
794 log_verbose("\nTesting get and set Attributes\n");
795 attr
=UNUM_GROUPING_SIZE
;
796 newvalue
=unum_getAttribute(def
, attr
);
798 unum_setAttribute(def
, attr
, newvalue
);
799 if(unum_getAttribute(def
,attr
)!=2)
800 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
802 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
804 attr
=UNUM_MULTIPLIER
;
805 newvalue
=unum_getAttribute(def
, attr
);
807 unum_setAttribute(def
, attr
, newvalue
);
808 if(unum_getAttribute(def
,attr
) != 8)
809 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
811 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
813 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
814 newvalue
=unum_getAttribute(def
, attr
);
816 unum_setAttribute(def
, attr
, newvalue
);
817 if(unum_getAttribute(def
,attr
) != 2)
818 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
819 unum_getAttribute(def
,attr
));
821 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
823 /*testing set and get Attributes extensively */
824 log_verbose("\nTesting get and set attributes extensively\n");
825 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
827 newvalue
=unum_getAttribute(fr
, attr
);
828 unum_setAttribute(def
, attr
, newvalue
);
829 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
830 log_err("error in setting and getting attributes\n");
832 log_verbose("Pass: attributes set and retrieved successfully\n");
835 /*testing spellout format to make sure we can use it successfully.*/
836 log_verbose("\nTesting spellout format\n");
839 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
840 for (i
= 0; i
< UPRV_LENGTHOF(values
); ++i
) {
843 int32_t value
= values
[i
];
844 status
= U_ZERO_ERROR
;
845 len
= unum_format(spellout_def
, value
, buffer
, UPRV_LENGTHOF(buffer
), NULL
, &status
);
846 if(U_FAILURE(status
)) {
847 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
851 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
852 log_verbose("formatted %d as '%s', length: %d\n", value
, aescstrdup(buffer
, len
), len
);
854 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
855 if (U_FAILURE(status
)) {
856 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
857 } else if (parseResult
!= value
) {
858 log_err("unum_format result %d != value %d\n", parseResult
, value
);
864 log_err("Spellout format is unavailable\n");
867 { /* Test for ticket #7079 */
868 UNumberFormat
* dec_en
;
869 UChar groupingSep
[] = { 0 };
870 UChar numPercent
[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
871 double parseResult
= 0.0;
874 dec_en
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
875 unum_setAttribute(dec_en
, UNUM_LENIENT_PARSE
, 0);
876 unum_setSymbol(dec_en
, UNUM_GROUPING_SEPARATOR_SYMBOL
, groupingSep
, 0, &status
);
877 parseResult
= unum_parseDouble(dec_en
, numPercent
, -1, NULL
, &status
);
878 /* Without the fix in #7079, the above call will hang */
879 if ( U_FAILURE(status
) || parseResult
!= 12.0 ) {
880 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
881 myErrorName(status
), parseResult
);
883 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
888 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
889 to verify that it is taking the pure decimal path. */
891 const char *bdpattern
= "#,##0.#########";
892 const char *numInitial
= "12345678900987654321.1234567896";
893 const char *numFormatted
= "12,345,678,900,987,654,321.12345679";
894 const char *parseExpected
= "1.234567890098765432112345679E+19";
895 const char *parseExpected2
= "3.4567890098765432112345679E+17";
896 int32_t resultSize
= 0;
897 int32_t parsePos
= 0; /* Output parameter for Parse operations. */
898 #define DESTCAPACITY 100
899 UChar dest
[DESTCAPACITY
];
900 char desta
[DESTCAPACITY
];
901 UFieldPosition fieldPos
= {0};
905 status
= U_ZERO_ERROR
;
906 u_uastrcpy(dest
, bdpattern
);
907 fmt
= unum_open(UNUM_PATTERN_DECIMAL
, dest
, -1, "en", NULL
/*parseError*/, &status
);
908 if (U_FAILURE(status
)) log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
910 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, NULL
, &status
);
911 if (U_FAILURE(status
)) {
912 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
914 u_austrncpy(desta
, dest
, DESTCAPACITY
);
915 if (strcmp(numFormatted
, desta
) != 0) {
916 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
917 __FILE__
, __LINE__
, numFormatted
, desta
);
919 if (strlen(numFormatted
) != resultSize
) {
920 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
921 __FILE__
, __LINE__
, strlen(numFormatted
), resultSize
);
924 /* Format with a FieldPosition parameter */
926 fieldPos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
927 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, &fieldPos
, &status
);
928 if (U_FAILURE(status
)) {
929 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
931 u_austrncpy(desta
, dest
, DESTCAPACITY
);
932 if (strcmp(numFormatted
, desta
) != 0) {
933 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
934 __FILE__
, __LINE__
, numFormatted
, desta
);
936 if (fieldPos
.beginIndex
!= 26) { /* index of "." in formatted number */
937 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
938 __FILE__
, __LINE__
, 0, fieldPos
.beginIndex
);
940 if (fieldPos
.endIndex
!= 27) {
941 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
942 __FILE__
, __LINE__
, 0, fieldPos
.endIndex
);
947 status
= U_ZERO_ERROR
;
948 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
949 resultSize
= unum_parseDecimal(fmt
, dest
, -1, NULL
, desta
, DESTCAPACITY
, &status
);
950 if (U_FAILURE(status
)) {
951 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
953 if (uprv_strcmp(parseExpected
, desta
) != 0) {
954 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
955 __FILE__
, __LINE__
, parseExpected
, desta
);
957 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
958 __FILE__
, __LINE__
, desta
);
960 if (strlen(parseExpected
) != resultSize
) {
961 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
962 __FILE__
, __LINE__
, strlen(parseExpected
), resultSize
);
965 /* Parse with a parsePos parameter */
967 status
= U_ZERO_ERROR
;
968 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
969 parsePos
= 3; /* 12,345,678,900,987,654,321.12345679 */
970 /* start parsing at the the third char */
971 resultSize
= unum_parseDecimal(fmt
, dest
, -1, &parsePos
, desta
, DESTCAPACITY
, &status
);
972 if (U_FAILURE(status
)) {
973 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
975 if (strcmp(parseExpected2
, desta
) != 0) { /* "3.4567890098765432112345679E+17" */
976 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
977 __FILE__
, __LINE__
, parseExpected2
, desta
);
979 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
980 __FILE__
, __LINE__
, desta
);
982 if (strlen(numFormatted
) != parsePos
) {
983 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
984 __FILE__
, __LINE__
, strlen(parseExpected
), parsePos
);
990 status
= U_ZERO_ERROR
;
991 /* Test invalid symbol argument */
993 int32_t badsymbolLarge
= UNUM_FORMAT_SYMBOL_COUNT
+ 1;
994 int32_t badsymbolSmall
= -1;
996 int32_t valueLength
= 10;
997 UNumberFormat
*fmt
= unum_open(UNUM_DEFAULT
, NULL
, 0, NULL
, NULL
, &status
);
998 if (U_FAILURE(status
)) {
999 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
1001 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, NULL
, 0, &status
);
1002 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
1004 status
= U_ZERO_ERROR
;
1005 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, NULL
, 0, &status
);
1006 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
1008 status
= U_ZERO_ERROR
;
1009 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, value
, valueLength
, &status
);
1010 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
1012 status
= U_ZERO_ERROR
;
1013 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, value
, valueLength
, &status
);
1014 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
1021 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
1024 unum_close(cur_def
);
1026 unum_close(per_def
);
1028 unum_close(spellout_def
);
1029 unum_close(pattern
);
1030 unum_close(cur_frpattern
);
1031 unum_close(myclone
);
1035 static void TestParseZero(void)
1037 UErrorCode errorCode
= U_ZERO_ERROR
;
1038 UChar input
[] = {0x30, 0}; /* Input text is decimal '0' */
1039 UChar pat
[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
1043 UNumberFormat
* unum
= unum_open( UNUM_DECIMAL
/*or UNUM_DEFAULT*/, NULL
, -1, NULL
, NULL
, &errorCode
);
1045 UNumberFormat
* unum
= unum_open( UNUM_PATTERN_DECIMAL
/*needs pattern*/, pat
, -1, NULL
, NULL
, &errorCode
);
1048 dbl
= unum_parseDouble( unum
, input
, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode
);
1049 if (U_FAILURE(errorCode
)) {
1050 log_data_err("Result - %s\n", u_errorName(errorCode
));
1052 log_verbose("Double: %f\n", dbl
);
1057 static const UChar dollars2Sym
[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
1058 static const UChar dollars4Sym
[] = { 0x24,0x34,0 }; /* $4 */
1059 static const UChar dollarsUS4Sym
[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
1060 static const UChar dollars9Sym
[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
1061 static const UChar pounds3Sym
[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
1062 static const UChar pounds5Sym
[] = { 0xA3,0x35,0 }; /* [POUND]5 */
1063 static const UChar pounds7Sym
[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
1064 static const UChar euros4Sym
[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
1065 static const UChar euros6Sym
[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
1066 static const UChar euros8Sym
[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
1067 static const UChar dollars4PluEn
[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
1068 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 */
1069 static const UChar euros8PluEn
[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
1070 static const UChar euros6PluFr
[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
1073 const char * locale
;
1074 const char * descrip
;
1075 const UChar
* currStr
;
1076 const UChar
* plurStr
;
1077 UErrorCode parsDoubExpectErr
;
1078 int32_t parsDoubExpectPos
;
1079 double parsDoubExpectVal
;
1080 UErrorCode parsCurrExpectErr
;
1081 int32_t parsCurrExpectPos
;
1082 double parsCurrExpectVal
;
1083 const char * parsCurrExpectCurr
;
1084 } ParseCurrencyItem
;
1086 static const ParseCurrencyItem parseCurrencyItems
[] = {
1087 { "en_US", "dollars2", dollars2Sym
, NULL
, U_ZERO_ERROR
, 5, 2.0, U_ZERO_ERROR
, 5, 2.0, "USD" },
1088 { "en_US", "dollars4", dollars4Sym
, dollars4PluEn
, U_ZERO_ERROR
, 2, 4.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1089 { "en_US", "dollars9", dollars9Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1090 { "en_US", "pounds3", pounds3Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1091 { "en_US", "pounds5", pounds5Sym
, pounds5PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1092 { "en_US", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1093 { "en_US", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1095 { "en_GB", "pounds3", pounds3Sym
, NULL
, U_ZERO_ERROR
, 5, 3.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1096 { "en_GB", "pounds5", pounds5Sym
, pounds5PluEn
, U_ZERO_ERROR
, 2, 5.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1097 { "en_GB", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1098 { "en_GB", "euros4", euros4Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1099 { "en_GB", "euros6", euros6Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1100 { "en_GB", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1101 { "en_GB", "dollars4", dollarsUS4Sym
,dollars4PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 4, 4.0, "USD" },
1103 { "fr_FR", "euros4", euros4Sym
, NULL
, U_ZERO_ERROR
, 6, 4.0, U_ZERO_ERROR
, 6, 4.0, "EUR" },
1104 { "fr_FR", "euros6", euros6Sym
, euros6PluFr
, U_ZERO_ERROR
, 3, 6.0, U_ZERO_ERROR
, 3, 6.0, "EUR" },
1105 { "fr_FR", "euros8", euros8Sym
, NULL
, U_PARSE_ERROR
, 2, 0.0, U_PARSE_ERROR
, 2, 0.0, "" },
1106 { "fr_FR", "dollars2", dollars2Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1107 { "fr_FR", "dollars4", dollars4Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1109 { NULL
, NULL
, NULL
, NULL
, 0, 0, 0.0, 0, 0, 0.0, NULL
}
1112 static void TestParseCurrency()
1114 const ParseCurrencyItem
* itemPtr
;
1115 for (itemPtr
= parseCurrencyItems
; itemPtr
->locale
!= NULL
; ++itemPtr
) {
1116 UNumberFormat
* unum
;
1123 status
= U_ZERO_ERROR
;
1124 unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1125 if (U_SUCCESS(status
)) {
1126 const UChar
* currStr
= itemPtr
->currStr
;
1127 status
= U_ZERO_ERROR
;
1129 parseVal
= unum_parseDouble(unum
, currStr
, -1, &parsePos
, &status
);
1130 if (status
!= itemPtr
->parsDoubExpectErr
|| parsePos
!= itemPtr
->parsDoubExpectPos
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1131 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1132 itemPtr
->locale
, itemPtr
->descrip
,
1133 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectPos
, itemPtr
->parsDoubExpectVal
,
1134 u_errorName(status
), parsePos
, parseVal
);
1136 status
= U_ZERO_ERROR
;
1139 parseVal
= unum_parseDoubleCurrency(unum
, currStr
, -1, &parsePos
, parseCurr
, &status
);
1140 u_austrncpy(parseCurrB
, parseCurr
, 4);
1141 if (status
!= itemPtr
->parsCurrExpectErr
|| parsePos
!= itemPtr
->parsCurrExpectPos
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1142 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1143 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1144 itemPtr
->locale
, itemPtr
->descrip
,
1145 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectPos
, itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1146 u_errorName(status
), parsePos
, parseVal
, parseCurrB
);
1150 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1153 if (itemPtr
->plurStr
!= NULL
) {
1154 status
= U_ZERO_ERROR
;
1155 unum
= unum_open(UNUM_CURRENCY_PLURAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1156 if (U_SUCCESS(status
)) {
1157 status
= U_ZERO_ERROR
;
1159 parseVal
= unum_parseDouble(unum
, itemPtr
->plurStr
, -1, &parsePos
, &status
);
1160 if (status
!= itemPtr
->parsDoubExpectErr
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1161 log_err("UNUM_CURRENCY parseDouble Plural %s/%s, expect %s val %.1f, get %s val %.1f\n",
1162 itemPtr
->locale
, itemPtr
->descrip
,
1163 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectVal
,
1164 u_errorName(status
), parseVal
);
1166 status
= U_ZERO_ERROR
;
1169 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->plurStr
, -1, &parsePos
, parseCurr
, &status
);
1170 u_austrncpy(parseCurrB
, parseCurr
, 4);
1171 if (status
!= itemPtr
->parsCurrExpectErr
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1172 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1173 log_err("UNUM_CURRENCY parseDoubleCurrency Plural %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1174 itemPtr
->locale
, itemPtr
->descrip
,
1175 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1176 u_errorName(status
), parseVal
, parseCurrB
);
1180 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1187 const char * testname
;
1188 const char * locale
;
1190 const UChar
* source
;
1197 static const UChar ustr_zh50d
[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1198 static const UChar ustr_zh05a
[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1199 static const UChar ustr_zh05d
[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1201 static const NumParseTestItem altnumParseTests
[] = {
1202 /* name loc lenent src start val end status */
1203 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_USING_DEFAULT_WARNING
},
1204 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_USING_DEFAULT_WARNING
},
1205 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_USING_DEFAULT_WARNING
},
1206 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1209 static void TestParseAltNum(void)
1211 const NumParseTestItem
* testPtr
;
1212 for (testPtr
= altnumParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1213 UErrorCode status
= U_ZERO_ERROR
;
1214 int32_t value
, position
= testPtr
->startPos
;
1215 UNumberFormat
*nf
= unum_open(UNUM_DECIMAL
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1216 if (U_FAILURE(status
)) {
1217 log_err_status(status
, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1220 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1221 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1222 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1223 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1224 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1225 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1226 value
, position
, myErrorName(status
) );
1232 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1233 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1234 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1235 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1236 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1237 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1238 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
1239 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1240 static const UChar ustr_zh50s
[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1241 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1242 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1243 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1245 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1247 static const NumParseTestItem spelloutParseTests
[] = {
1248 /* name loc lenent src start val end status */
1249 { "en0", "en", FALSE
, ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
1250 { "en0", "en", FALSE
, ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
1251 { "en0", "ja", FALSE
, ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
1252 #if NUMERIC_STRINGS_NOT_PARSEABLE
1253 { "123", "en", FALSE
, ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
1255 { "123", "en", FALSE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1257 { "123L", "en", TRUE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1258 { "en123", "en", FALSE
, ustr_en123
, 0, 123, 24, U_ZERO_ERROR
},
1259 { "en123", "en", FALSE
, ustr_en123
, 12, 23, 24, U_ZERO_ERROR
},
1260 { "en123", "fr", FALSE
, ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
1261 { "fr123", "fr", FALSE
, ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
1262 { "fr123", "fr", FALSE
, ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
1263 { "fr123", "en", FALSE
, ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
1264 { "ja123", "ja", FALSE
, ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
1265 { "ja123", "ja", FALSE
, ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
1266 { "ja123", "fr", FALSE
, ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
1267 { "zh,50s", "zh", FALSE
, ustr_zh50s
, 0, 50, 2, U_ZERO_ERROR
},
1268 // from ICU50m2, NUMERIC_STRINGS_NOT_PARSEABLE no longer affects the next three
1269 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1270 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1271 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1272 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1273 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1274 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1275 { "zh,50dL","zh", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1276 { "zh,05aL","zh", TRUE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1277 { "zh,05dL","zh", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1278 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1281 static void TestSpelloutNumberParse()
1283 const NumParseTestItem
* testPtr
;
1284 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1285 UErrorCode status
= U_ZERO_ERROR
;
1286 int32_t value
, position
= testPtr
->startPos
;
1287 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1288 if (U_FAILURE(status
)) {
1289 log_err_status(status
, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1292 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1293 status
= U_ZERO_ERROR
;
1294 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1295 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1296 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1297 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1298 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1299 value
, position
, myErrorName(status
) );
1305 static void TestSignificantDigits()
1308 int32_t resultlengthneeded
;
1309 int32_t resultlength
;
1310 UErrorCode status
= U_ZERO_ERROR
;
1311 UChar
*result
= NULL
;
1313 double d
= 123456.789;
1315 u_uastrcpy(temp
, "###0.0#");
1316 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, "en", NULL
, &status
);
1317 if (U_FAILURE(status
)) {
1318 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1321 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1322 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
1324 u_uastrcpy(temp
, "123457");
1326 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
1327 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1329 status
=U_ZERO_ERROR
;
1330 resultlength
=resultlengthneeded
+1;
1331 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1332 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
1334 if(U_FAILURE(status
))
1336 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1339 if(u_strcmp(result
, temp
)==0)
1340 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1342 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1347 static void TestSigDigRounding()
1349 UErrorCode status
= U_ZERO_ERROR
;
1350 UChar expected
[128];
1357 fmt
=unum_open(UNUM_DECIMAL
, NULL
, 0, "en", NULL
, &status
);
1358 if (U_FAILURE(status
)) {
1359 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1362 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, FALSE
);
1363 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1364 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2);
1365 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1367 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_UP
);
1368 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, 20.0);
1370 (void)unum_formatDouble(fmt
, d
, result
, UPRV_LENGTHOF(result
), NULL
, &status
);
1371 if(U_FAILURE(status
))
1373 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1377 u_uastrcpy(expected
, "140");
1378 if(u_strcmp(result
, expected
)!=0)
1379 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1
, result
), u_austrcpy(temp2
, expected
) );
1384 static void TestNumberFormatPadding()
1390 UErrorCode status
=U_ZERO_ERROR
;
1391 int32_t resultlength
;
1392 int32_t resultlengthneeded
;
1393 UNumberFormat
*pattern
;
1395 double d
= -10456.37;
1396 UFieldPosition pos1
;
1399 /* create a number format using unum_openPattern(....)*/
1400 log_verbose("\nTesting unum_openPattern() with padding\n");
1401 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
1402 status
=U_ZERO_ERROR
;
1403 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
1404 if(U_SUCCESS(status
))
1406 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );
1410 unum_close(pattern
);
1413 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1414 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
1415 u_uastrcpy(temp2
, "*x#########,##0.0#;(#########,##0.0#)"); // equivalent (?) output pattern
1416 status
=U_ZERO_ERROR
;
1417 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
1418 if(U_FAILURE(status
))
1420 log_err_status(status
, "error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
1423 log_verbose("Pass: padding unum_openPattern() works fine\n");
1425 /*test for unum_toPattern()*/
1426 log_verbose("\nTesting padding unum_toPattern()\n");
1428 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
1429 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1431 status
=U_ZERO_ERROR
;
1432 resultlength
=resultlengthneeded
+1;
1433 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1434 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
1436 if(U_FAILURE(status
))
1438 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
1442 if(u_strncmp(result
, temp2
, resultlengthneeded
)!=0) {
1444 "FAIL: Error in extracting the padding pattern using unum_toPattern(): %d: %s != %s\n",
1449 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1453 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1454 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
1456 pos1
.field
= UNUM_FRACTION_FIELD
;
1457 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
1458 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1460 status
=U_ZERO_ERROR
;
1461 resultlength
=resultlengthneeded
+1;
1462 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1463 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
1465 if(U_FAILURE(status
))
1467 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
1471 if(u_strcmp(result
, temp1
)==0)
1472 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1474 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1475 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
1476 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1478 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1479 pos1
.beginIndex
, pos1
.endIndex
);
1482 /* Testing unum_parse() and unum_parseDouble() */
1483 log_verbose("\nTesting padding unum_parseDouble()\n");
1485 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
1486 if(U_FAILURE(status
))
1488 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
1492 log_err("Fail: Error in padding parsing\n");
1494 log_verbose("Pass: padding parsing successful\n");
1499 unum_close(pattern
);
1503 withinErr(double a
, double b
, double err
) {
1504 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
1507 static void TestInt64Format() {
1511 UErrorCode status
= U_ZERO_ERROR
;
1512 const double doubleInt64Max
= (double)U_INT64_MAX
;
1513 const double doubleInt64Min
= (double)U_INT64_MIN
;
1514 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
1520 /* create a number format using unum_openPattern(....) */
1521 log_verbose("\nTesting Int64Format\n");
1522 u_uastrcpy(temp1
, "#.#E0");
1523 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), "en_US", NULL
, &status
);
1524 if(U_FAILURE(status
)) {
1525 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status
));
1527 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1528 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1529 if (U_FAILURE(status
)) {
1530 log_err("error in unum_format(): %s\n", myErrorName(status
));
1532 log_verbose("format int64max: '%s'\n", result
);
1534 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1535 if (status
!= U_INVALID_FORMAT_ERROR
) {
1536 log_err("parse didn't report error: %s\n", myErrorName(status
));
1537 } else if (val32
!= INT32_MAX
) {
1538 log_err("parse didn't pin return value, got: %d\n", val32
);
1541 status
= U_ZERO_ERROR
;
1543 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1544 if (U_FAILURE(status
)) {
1545 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1546 } else if (val64
!= U_INT64_MAX
) {
1547 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1550 status
= U_ZERO_ERROR
;
1552 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1553 if (U_FAILURE(status
)) {
1554 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1555 } else if (valDouble
!= doubleInt64Max
) {
1556 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1560 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1561 if (U_FAILURE(status
)) {
1562 log_err("error in unum_format(): %s\n", myErrorName(status
));
1564 log_verbose("format int64min: '%s'\n", result
);
1566 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1567 if (status
!= U_INVALID_FORMAT_ERROR
) {
1568 log_err("parse didn't report error: %s\n", myErrorName(status
));
1569 } else if (val32
!= INT32_MIN
) {
1570 log_err("parse didn't pin return value, got: %d\n", val32
);
1573 status
= U_ZERO_ERROR
;
1575 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1576 if (U_FAILURE(status
)) {
1577 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1578 } else if (val64
!= U_INT64_MIN
) {
1579 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1582 status
= U_ZERO_ERROR
;
1584 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1585 if (U_FAILURE(status
)) {
1586 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1587 } else if (valDouble
!= doubleInt64Min
) {
1588 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1592 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1593 if (U_FAILURE(status
)) {
1594 log_err("error in unum_format(): %s\n", myErrorName(status
));
1596 log_verbose("format doubleBig: '%s'\n", result
);
1598 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1599 if (status
!= U_INVALID_FORMAT_ERROR
) {
1600 log_err("parse didn't report error: %s\n", myErrorName(status
));
1601 } else if (val32
!= INT32_MAX
) {
1602 log_err("parse didn't pin return value, got: %d\n", val32
);
1605 status
= U_ZERO_ERROR
;
1607 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1608 if (status
!= U_INVALID_FORMAT_ERROR
) {
1609 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1610 } else if (val64
!= U_INT64_MAX
) {
1611 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1614 status
= U_ZERO_ERROR
;
1616 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1617 if (U_FAILURE(status
)) {
1618 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1619 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1620 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1624 u_uastrcpy(result
, "5.06e-27");
1626 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1627 if (U_FAILURE(status
)) {
1628 log_err("parseDouble() returned error: %s\n", myErrorName(status
));
1629 } else if (!withinErr(valDouble
, 5.06e-27, 1e-15)) {
1630 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble
);
1637 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1640 int32_t BUFSIZE
= UPRV_LENGTHOF(buffer
);
1642 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1646 for (i
= 0; i
< UPRV_LENGTHOF(vals
); ++i
) {
1647 UErrorCode status
= U_ZERO_ERROR
;
1648 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1649 if (U_FAILURE(status
)) {
1650 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1652 u_austrcpy(temp
, buffer
);
1653 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1657 /* check APIs now */
1659 UErrorCode status
= U_ZERO_ERROR
;
1661 u_uastrcpy(buffer
, "#,##0.0#");
1662 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1663 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1664 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1669 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1670 log_verbose("lenient: 0x%x\n", isLenient
);
1671 if (isLenient
!= FALSE
) {
1672 log_err("didn't expect lenient value: %d\n", isLenient
);
1675 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1676 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1677 if (isLenient
!= TRUE
) {
1678 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1684 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1686 log_err("didn't expect double attribute\n");
1688 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1689 if ((val
== -1) == isDecimal
) {
1690 log_err("didn't expect -1 rounding increment\n");
1692 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1693 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1694 if (isDecimal
&& (val2
- val
!= .5)) {
1695 log_err("set rounding increment had no effect on decimal format");
1700 UErrorCode status
= U_ZERO_ERROR
;
1701 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1702 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1703 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1705 if (U_SUCCESS(status
)) {
1706 u_austrcpy(temp
, buffer
);
1707 log_verbose("default ruleset: '%s'\n", temp
);
1710 status
= U_ZERO_ERROR
;
1711 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1712 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1713 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1715 if (U_SUCCESS(status
)) {
1716 u_austrcpy(temp
, buffer
);
1717 log_verbose("public rulesets: '%s'\n", temp
);
1719 /* set the default ruleset to the first one found, and retry */
1722 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1725 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1726 if (U_FAILURE(status
)) {
1727 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1729 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1730 if (U_FAILURE(status
)) {
1731 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1732 } else if (len2
!= i
) {
1733 u_austrcpy(temp
, buffer
);
1734 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1736 for (i
= 0; i
< UPRV_LENGTHOF(vals
); ++i
) {
1737 status
= U_ZERO_ERROR
;
1738 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1739 if (U_FAILURE(status
)) {
1740 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1742 u_austrcpy(temp
, buffer
);
1743 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1754 UErrorCode status
= U_ZERO_ERROR
;
1755 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1756 if (U_SUCCESS(status
)) {
1757 u_austrcpy(temp
, buffer
);
1758 log_verbose("pattern: '%s'\n", temp
);
1759 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1760 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1762 log_verbose("pattern too long to display\n");
1767 UErrorCode status
= U_ZERO_ERROR
;
1768 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1769 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1770 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1773 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1774 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1775 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1780 static void TestNonExistentCurrency() {
1781 UNumberFormat
*format
;
1782 UErrorCode status
= U_ZERO_ERROR
;
1783 UChar currencySymbol
[8];
1784 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1786 /* Get a non-existent currency and make sure it returns the correct currency code. */
1787 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1788 if (format
== NULL
|| U_FAILURE(status
)) {
1789 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status
));
1792 unum_getSymbol(format
,
1793 UNUM_CURRENCY_SYMBOL
,
1795 UPRV_LENGTHOF(currencySymbol
),
1797 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1798 log_err("unum_open set the currency to QQQ\n");
1804 static void TestRBNFFormat() {
1808 UChar tempUChars
[512];
1809 UNumberFormat
*formats
[5];
1810 int COUNT
= UPRV_LENGTHOF(formats
);
1813 for (i
= 0; i
< COUNT
; ++i
) {
1818 status
= U_ZERO_ERROR
;
1819 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1820 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1821 if (U_FAILURE(status
)) {
1822 log_err_status(status
, "unable to open decimal pattern -> %s\n", u_errorName(status
));
1826 status
= U_ZERO_ERROR
;
1827 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1828 if (U_FAILURE(status
)) {
1829 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1833 status
= U_ZERO_ERROR
;
1834 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1835 if (U_FAILURE(status
)) {
1836 log_err_status(status
, "unable to open ordinal -> %s\n", u_errorName(status
));
1840 status
= U_ZERO_ERROR
;
1841 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1842 if (U_FAILURE(status
)) {
1843 log_err_status(status
, "unable to open duration %s\n", u_errorName(status
));
1847 status
= U_ZERO_ERROR
;
1851 "x.x: << point >>;\n"
1852 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1853 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1854 "seventeen; eighteen; nineteen;\n"
1855 "20: twenty[->>];\n"
1856 "30: thirty[->>];\n"
1860 "70: seventy[->>];\n"
1861 "80: eighty[->>];\n"
1862 "90: ninety[->>];\n"
1864 u_uastrcpy(tempUChars
,
1867 "20: twenty[ and change];\n"
1868 "30: thirty[ and change];\n"
1869 "40: forty[ and change];\n"
1870 "50: fifty[ and change];\n"
1871 "60: sixty[ and change];\n"
1872 "70: seventy[ and change];\n"
1873 "80: eighty[ and change];\n"
1874 "90: ninety[ and change];\n"
1878 "x.x: << point something;\n"
1880 "20: some reasonable number;\n"
1881 "100: some substantial number;\n"
1882 "100,000,000: some huge number;\n");
1883 /* This is to get around some compiler warnings about char * string length. */
1884 u_strcat(pat
, tempUChars
);
1885 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1886 if (U_FAILURE(status
)) {
1887 log_err_status(status
, "unable to open rulebased pattern -> %s\n", u_errorName(status
));
1889 if (U_FAILURE(status
)) {
1890 log_err_status(status
, "Something failed with %s\n", u_errorName(status
));
1894 for (i
= 0; i
< COUNT
; ++i
) {
1895 log_verbose("\n\ntesting format %d\n", i
);
1896 test_fmt(formats
[i
], (UBool
)(i
== 0));
1899 #define FORMAT_BUF_CAPACITY 64
1901 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1903 double nanvalue
= uprv_getNaN();
1904 status
= U_ZERO_ERROR
;
1905 len
= unum_formatDouble(formats
[1], nanvalue
, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1906 if (U_FAILURE(status
)) {
1907 log_err_status(status
, "unum_formatDouble NAN failed with %s\n", u_errorName(status
));
1909 UChar nansym
[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1910 if ( len
!= 3 || u_strcmp(fmtbuf
, nansym
) != 0 ) {
1911 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1916 for (i
= 0; i
< COUNT
; ++i
) {
1917 unum_close(formats
[i
]);
1921 static void TestRBNFRounding() {
1922 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1923 UChar expectedBuf
[FORMAT_BUF_CAPACITY
];
1925 UErrorCode status
= U_ZERO_ERROR
;
1926 UNumberFormat
* fmt
= unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", NULL
, &status
);
1927 if (U_FAILURE(status
)) {
1928 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1931 len
= unum_formatDouble(fmt
, 10.123456789, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1932 U_ASSERT(len
< FORMAT_BUF_CAPACITY
);
1933 if (U_FAILURE(status
)) {
1934 log_err_status(status
, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status
));
1936 u_uastrcpy(expectedBuf
, "ten point one two three four five six seven eight nine");
1937 if (u_strcmp(expectedBuf
, fmtbuf
) != 0) {
1938 log_err("Wrong result for unrounded value\n");
1940 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 3);
1941 if (unum_getAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
) != 3) {
1942 log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
));
1944 if (unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
) != UNUM_ROUND_UNNECESSARY
) {
1945 log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
));
1947 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_HALFUP
);
1948 if (unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
) != UNUM_ROUND_HALFUP
) {
1949 log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt
, UNUM_ROUNDING_MODE
));
1951 len
= unum_formatDouble(fmt
, 10.123456789, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1952 U_ASSERT(len
< FORMAT_BUF_CAPACITY
);
1953 if (U_FAILURE(status
)) {
1954 log_err_status(status
, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status
));
1956 u_uastrcpy(expectedBuf
, "ten point one two three");
1957 if (u_strcmp(expectedBuf
, fmtbuf
) != 0) {
1959 u_austrcpy(temp
, fmtbuf
);
1960 log_err("Wrong result for rounded value. Got: %s\n", temp
);
1965 static void TestCurrencyRegression(void) {
1967 I've found a case where unum_parseDoubleCurrency is not doing what I
1968 expect. The value I pass in is $1234567890q123460000.00 and this
1969 returns with a status of zero error & a parse pos of 22 (I would
1970 expect a parse error at position 11).
1972 I stepped into DecimalFormat::subparse() and it looks like it parses
1973 the first 10 digits and then stops parsing at the q but doesn't set an
1974 error. Then later in DecimalFormat::parse() the value gets crammed
1975 into a long (which greatly truncates the value).
1977 This is very problematic for me 'cause I try to remove chars that are
1978 invalid but this allows my users to enter bad chars and truncates
1988 UErrorCode status
= U_ZERO_ERROR
;
1989 const int32_t expected
= 11;
1992 u_uastrcpy(buf
, "$1234567890q643210000.00");
1993 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1995 if(U_FAILURE(status
)) {
1996 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status
));
2000 status
= U_ZERO_ERROR
; /* so we can test it later. */
2003 d
= unum_parseDoubleCurrency(cur
,
2006 &pos
, /* 0 = start */
2010 u_austrcpy(acurrency
, currency
);
2012 if(U_FAILURE(status
) || (pos
!= expected
)) {
2013 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
2014 expected
, d
, u_errorName(status
), pos
, acurrency
);
2016 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
2022 static void TestTextAttributeCrash(void) {
2023 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
2024 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
2025 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
2027 UErrorCode status
= U_ZERO_ERROR
;
2028 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
2029 if (U_FAILURE(status
)) {
2030 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status
));
2033 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
2035 * the usual negative prefix and suffix seem to be '($' and ')' at this point
2036 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
2038 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
2039 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
2040 if (U_FAILURE(status
)) {
2041 log_err("FAILED 2\n"); exit(1);
2043 log_verbose("attempting to format...\n");
2044 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
2045 if (U_FAILURE(status
) || 64 < used
) {
2046 log_err("Failed formatting %s\n", u_errorName(status
));
2049 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
2050 log_err("Didn't get expected negative result\n");
2052 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
2053 if (U_FAILURE(status
) || 64 < used
) {
2054 log_err("Failed formatting %s\n", u_errorName(status
));
2057 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
2058 log_err("Didn't get expected positive result\n");
2063 static void TestNBSPPatternRtNum(const char *testcase
, int line
, UNumberFormat
*nf
, double myNumber
) {
2064 UErrorCode status
= U_ZERO_ERROR
;
2067 double aNumber
= -1.0;
2068 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
2069 log_verbose("%s:%d: formatted %.2f into %s\n", testcase
, line
, myNumber
, u_austrcpy(tmpbuf
, myString
));
2070 if(U_FAILURE(status
)) {
2071 log_err("%s:%d: failed format of %.2g with %s\n", testcase
, line
, myNumber
, u_errorName(status
));
2074 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
2075 if(U_FAILURE(status
)) {
2076 log_err("%s:%d: failed parse with %s\n", testcase
, line
, u_errorName(status
));
2079 if(uprv_fabs(aNumber
-myNumber
)>.001) {
2080 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
2082 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
2086 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
2087 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, 12345.);
2088 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, -12345.);
2091 static void TestNBSPInPattern(void) {
2092 UErrorCode status
= U_ZERO_ERROR
;
2093 UNumberFormat
* nf
= NULL
;
2094 const char *testcase
;
2097 testcase
="ar_AE UNUM_CURRENCY";
2098 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
2099 if(U_FAILURE(status
) || nf
== NULL
) {
2100 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, testcase
, u_errorName(status
));
2103 TestNBSPPatternRT(testcase
, nf
);
2105 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
2107 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
2109 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
2110 u_unescape(SPECIAL_PATTERN
, pat
, UPRV_LENGTHOF(pat
));
2111 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
2112 if(U_FAILURE(status
)) {
2113 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
2115 TestNBSPPatternRT(testcase
, nf
);
2117 #undef SPECIAL_PATTERN
2119 unum_close(nf
); status
= U_ZERO_ERROR
;
2121 testcase
="ar_AE UNUM_DECIMAL";
2122 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
2123 if(U_FAILURE(status
)) {
2124 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2126 TestNBSPPatternRT(testcase
, nf
);
2127 unum_close(nf
); status
= U_ZERO_ERROR
;
2129 testcase
="ar_AE UNUM_PERCENT";
2130 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
2131 if(U_FAILURE(status
)) {
2132 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2134 TestNBSPPatternRT(testcase
, nf
);
2135 unum_close(nf
); status
= U_ZERO_ERROR
;
2140 static void TestCloneWithRBNF(void) {
2141 UChar pattern
[1024];
2143 UErrorCode status
= U_ZERO_ERROR
;
2145 UChar buffer_cloned
[256];
2148 UNumberFormat
*pform_cloned
;
2149 UNumberFormat
*pform
;
2153 "0.x: >%%millis-only>;\n"
2154 "x.0: <%%duration<;\n"
2155 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2156 "-x: ->>;%%millis-only:\n"
2157 "1000: 00:00.<%%millis<;\n"
2159 "1000: .<%%millis<;\n"
2163 "0: =%%seconds-only=;\n"
2164 "60: =%%min-sec=;\n"
2165 "3600: =%%hr-min-sec=;\n"
2166 "86400/86400: <%%ddaayyss<[, >>];\n"
2167 "%%durationwithmillis:\n"
2168 "0: =%%seconds-only=;\n"
2169 "60: =%%min-sec=;\n"
2170 "3600: =%%hr-min-sec=;\n"
2171 "86400/86400: <%%ddaayyss<, >>;\n");
2181 "3600/60: <0<:>>>;\n"
2187 /* This is to get around some compiler warnings about char * string length. */
2188 u_strcat(pattern
, pat2
);
2190 pform
= unum_open(UNUM_PATTERN_RULEBASED
, pattern
, -1, "en_US", NULL
, &status
);
2191 unum_formatDouble(pform
, 3600, buffer
, 256, NULL
, &status
);
2193 pform_cloned
= unum_clone(pform
,&status
);
2194 unum_formatDouble(pform_cloned
, 3600, buffer_cloned
, 256, NULL
, &status
);
2197 unum_close(pform_cloned
);
2199 if (u_strcmp(buffer
,buffer_cloned
)) {
2200 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
));
2205 static void TestNoExponent(void) {
2206 UErrorCode status
= U_ZERO_ERROR
;
2214 fmt
= unum_open(UNUM_DECIMAL
, NULL
, -1, "en_US", NULL
, &status
);
2216 if(U_FAILURE(status
) || fmt
== NULL
) {
2217 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
));
2222 u_uastrcpy(str
, cstr
);
2225 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2226 ASSERT_TRUE(pos
==4);
2227 if(U_FAILURE(status
)) {
2228 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2229 } else if(expect
!=num
) {
2230 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2232 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2235 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2237 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2238 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2240 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2244 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2246 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__
, __LINE__
, cstr
);
2247 } else if(num
==expect
) {
2248 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__
, __LINE__
, num
, cstr
);
2250 ASSERT_TRUE(pos
==2);
2252 status
= U_ZERO_ERROR
;
2256 /* ok, now try scientific */
2257 fmt
= unum_open(UNUM_SCIENTIFIC
, NULL
, -1, "en_US", NULL
, &status
);
2258 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status
);
2260 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2263 u_uastrcpy(str
, cstr
);
2266 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2267 ASSERT_TRUE(pos
==4);
2268 if(U_FAILURE(status
)) {
2269 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2270 } else if(expect
!=num
) {
2271 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2273 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2276 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2277 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2279 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2281 // A scientific formatter should parse the exponent even if UNUM_PARSE_NO_EXPONENT is set
2283 u_uastrcpy(str
, cstr
);
2286 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2287 ASSERT_TRUE(pos
==4);
2288 if(U_FAILURE(status
)) {
2289 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2290 } else if(expect
!=num
) {
2291 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2293 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2299 static void TestMaxInt(void) {
2300 UErrorCode status
= U_ZERO_ERROR
;
2301 UChar pattern_hash
[] = { 0x23, 0x00 }; /* "#" */
2302 UChar result1
[1024] = { 0 }, result2
[1024] = { 0 };
2304 UChar expect
[] = { 0x0039, 0x0037, 0 };
2305 UNumberFormat
*fmt
= unum_open(
2306 UNUM_PATTERN_DECIMAL
, /* style */
2307 &pattern_hash
[0], /* pattern */
2308 u_strlen(pattern_hash
), /* patternLength */
2312 if(U_FAILURE(status
) || fmt
== NULL
) {
2313 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, "TestMaxInt", u_errorName(status
));
2317 unum_setAttribute(fmt
, UNUM_MAX_INTEGER_DIGITS
, 2);
2319 status
= U_ZERO_ERROR
;
2321 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2323 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2324 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2327 status
= U_ZERO_ERROR
;
2329 len2
= unum_formatDouble(fmt
, 1997.0, result2
, 1024, NULL
, &status
);
2331 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2332 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2337 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2338 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==0);
2340 unum_setAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
, 1);
2341 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2342 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==1);
2344 status
= U_ZERO_ERROR
;
2345 /* max int digits still '2' */
2346 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2347 ASSERT_TRUE(status
==U_ILLEGAL_ARGUMENT_ERROR
);
2348 status
= U_ZERO_ERROR
;
2350 /* But, formatting 97->'97' works fine. */
2353 len1
= unum_formatInt64(fmt
, 97, result1
, 1024, NULL
, &status
);
2355 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2356 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2359 status
= U_ZERO_ERROR
;
2361 len2
= unum_formatDouble(fmt
, 97.0, result2
, 1024, NULL
, &status
);
2363 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2364 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2371 static void TestSignAlwaysShown(void) {
2372 UErrorCode status
= U_ZERO_ERROR
;
2373 UNumberFormat
*fmt
= unum_open(
2374 UNUM_DECIMAL
, /* style */
2376 0, /* patternLength */
2378 NULL
, /* parseErr */
2380 assertSuccess("Creating UNumberFormat", &status
);
2381 unum_setAttribute(fmt
, UNUM_SIGN_ALWAYS_SHOWN
, 1);
2383 unum_formatDouble(fmt
, 42, result
, 100, NULL
, &status
);
2384 assertSuccess("Formatting with UNumberFormat", &status
);
2385 assertUEquals("Result with sign always shown", u
"+42", result
);
2389 static void TestMinimumGroupingDigits(void) {
2390 UErrorCode status
= U_ZERO_ERROR
;
2391 UNumberFormat
*fmt
= unum_open(
2392 UNUM_DECIMAL
, /* style */
2394 0, /* patternLength */
2396 NULL
, /* parseErr */
2398 assertSuccess("Creating UNumberFormat", &status
);
2399 unum_setAttribute(fmt
, UNUM_MINIMUM_GROUPING_DIGITS
, 2);
2401 unum_formatDouble(fmt
, 1234, result
, 100, NULL
, &status
);
2402 assertSuccess("Formatting with UNumberFormat A", &status
);
2403 assertUEquals("Result with minimum grouping digits A", u
"1234", result
);
2404 unum_formatDouble(fmt
, 12345, result
, 100, NULL
, &status
);
2405 assertSuccess("Formatting with UNumberFormat B", &status
);
2406 assertUEquals("Result with minimum grouping digits B", u
"12,345", result
);
2410 static void TestParseCaseSensitive(void) {
2411 UErrorCode status
= U_ZERO_ERROR
;
2412 UNumberFormat
*fmt
= unum_open(
2413 UNUM_DECIMAL
, /* style */
2415 0, /* patternLength */
2417 NULL
, /* parseErr */
2419 assertSuccess("Creating UNumberFormat", &status
);
2420 double result
= unum_parseDouble(fmt
, u
"1e2", -1, NULL
, &status
);
2421 assertSuccess("Parsing with UNumberFormat, case insensitive", &status
);
2422 assertIntEquals("Result with case sensitive", 100, (int64_t)result
);
2423 unum_setAttribute(fmt
, UNUM_PARSE_CASE_SENSITIVE
, 1);
2425 result
= unum_parseDouble(fmt
, u
"1e2", -1, &ppos
, &status
);
2426 assertSuccess("Parsing with UNumberFormat, case sensitive", &status
);
2427 assertIntEquals("Position with case sensitive", 1, ppos
);
2428 assertIntEquals("Result with case sensitive", 1, (int64_t)result
);
2432 static void TestUFormattable(void) {
2434 // simple test for API docs
2436 UErrorCode status
= U_ZERO_ERROR
;
2437 UNumberFormat
*unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2438 if(assertSuccessCheck("calling unum_open()", &status
, TRUE
)) {
2439 //! [unum_parseToUFormattable]
2440 const UChar str
[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2442 UFormattable
*ufmt
= ufmt_open(&status
);
2443 unum_parseToUFormattable(unum
, ufmt
, str
, -1, NULL
, &status
);
2444 if (ufmt_isNumeric(ufmt
)) {
2445 result
= ufmt_getLong(ufmt
, &status
); /* == 123 */
2446 } /* else { ... } */
2448 //! [unum_parseToUFormattable]
2449 assertTrue("result == 123", (result
== 123));
2453 // test with explicitly created ufmt_open
2456 UErrorCode status
= U_ZERO_ERROR
;
2458 UNumberFormat
*unum
;
2459 const char *pattern
= "";
2461 ufmt
= ufmt_open(&status
);
2462 unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2463 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status
, TRUE
)) {
2466 log_verbose("-- pattern: %s\n", pattern
);
2467 u_uastrcpy(buffer
, pattern
);
2468 unum_parseToUFormattable(unum
, ufmt
, buffer
, -1, NULL
, &status
);
2469 if(assertSuccess("unum_parseToUFormattable(31337)", &status
)) {
2470 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt
, &status
) == 31337);
2471 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt
, &status
) == UFMT_LONG
);
2472 log_verbose("long = %d\n", ufmt_getLong(ufmt
, &status
));
2473 assertSuccess("ufmt_getLong()", &status
);
2475 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2476 if(assertSuccess("unum_formatUFormattable(31337)", &status
)) {
2477 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2480 pattern
= "3.14159";
2481 log_verbose("-- pattern: %s\n", pattern
);
2482 u_uastrcpy(buffer
, pattern
);
2483 unum_parseToUFormattable(unum
, ufmt
, buffer
, -1, NULL
, &status
);
2484 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status
)) {
2485 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt
, &status
), 3.14159, 1e-15));
2486 assertSuccess("ufmt_getDouble()", &status
);
2487 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt
, &status
) == UFMT_DOUBLE
);
2488 log_verbose("double = %g\n", ufmt_getDouble(ufmt
, &status
));
2490 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2491 if(assertSuccess("unum_formatUFormattable(3.14159)", &status
)) {
2492 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2499 // test with auto-generated ufmt
2502 UErrorCode status
= U_ZERO_ERROR
;
2503 UFormattable
*ufmt
= NULL
;
2504 UNumberFormat
*unum
;
2505 const char *pattern
= "73476730924573500000000"; // weight of the moon, kg
2507 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern
);
2508 u_uastrcpy(buffer
, pattern
);
2510 unum
= unum_open(UNUM_DEFAULT
, NULL
, -1, "en_US_POSIX", NULL
, &status
);
2511 if(assertSuccessCheck("calling unum_open()", &status
, TRUE
)) {
2513 ufmt
= unum_parseToUFormattable(unum
, NULL
, /* will be ufmt_open()'ed for us */
2514 buffer
, -1, NULL
, &status
);
2515 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status
)) {
2516 log_verbose("new formattable allocated at %p\n", (void*)ufmt
);
2517 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt
));
2518 unum_formatUFormattable(unum
, ufmt
, out2k
, 2048, NULL
, &status
);
2519 if(assertSuccess("unum_formatUFormattable(3.14159)", &status
)) {
2520 assertEquals("unum_formatUFormattable r/t", austrdup(buffer
), austrdup(out2k
));
2523 log_verbose("double: %g\n", ufmt_getDouble(ufmt
, &status
));
2524 assertSuccess("ufmt_getDouble()", &status
);
2526 log_verbose("long: %ld\n", ufmt_getLong(ufmt
, &status
));
2527 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status
));
2528 // status is now a failure due to ufmt_getLong() above.
2529 // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2534 ufmt_close(ufmt
); // was implicitly opened for us by the first unum_parseToUFormattable()
2542 UBool isAlgorithmic
;
2543 const UChar
* description
;
2547 static const UChar latnDesc
[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2548 static const UChar romanDesc
[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2549 static const UChar arabDesc
[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2550 static const UChar arabextDesc
[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2551 static const UChar hanidecDesc
[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2552 static const UChar hantDesc
[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2553 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2554 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2556 static const NumSysTestItem numSysTestItems
[] = {
2557 //locale numsys radix isAlgo description
2558 { "en", "latn", 10, FALSE
, latnDesc
},
2559 { "en@numbers=roman", "roman", 10, TRUE
, romanDesc
},
2560 { "en@numbers=finance", "latn", 10, FALSE
, latnDesc
},
2561 { "ar-EG", "arab", 10, FALSE
, arabDesc
},
2562 { "fa", "arabext", 10, FALSE
, arabextDesc
},
2563 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE
, hanidecDesc
},
2564 { "zh_Hant@numbers=traditional", "hant", 10, TRUE
, hantDesc
},
2565 { NULL
, NULL
, 0, FALSE
, NULL
},
2567 enum { kNumSysDescripBufMax
= 64 };
2569 static void TestUNumberingSystem(void) {
2570 const NumSysTestItem
* itemPtr
;
2571 UNumberingSystem
* unumsys
;
2572 UEnumeration
* uenum
;
2573 const char * numsys
;
2576 for (itemPtr
= numSysTestItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
2577 status
= U_ZERO_ERROR
;
2578 unumsys
= unumsys_open(itemPtr
->locale
, &status
);
2579 if ( U_SUCCESS(status
) ) {
2580 UChar ubuf
[kNumSysDescripBufMax
];
2581 int32_t ulen
, radix
= unumsys_getRadix(unumsys
);
2582 UBool isAlgorithmic
= unumsys_isAlgorithmic(unumsys
);
2583 numsys
= unumsys_getName(unumsys
);
2584 if ( uprv_strcmp(numsys
, itemPtr
->numsys
) != 0 || radix
!= itemPtr
->radix
|| !isAlgorithmic
!= !itemPtr
->isAlgorithmic
) {
2585 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2586 itemPtr
->locale
, itemPtr
->numsys
, itemPtr
->radix
, itemPtr
->isAlgorithmic
, numsys
, radix
, isAlgorithmic
);
2588 ulen
= unumsys_getDescription(unumsys
, ubuf
, kNumSysDescripBufMax
, &status
);
2589 (void)ulen
; // Suppress variable not used warning.
2590 if ( U_FAILURE(status
) || u_strcmp(ubuf
, itemPtr
->description
) != 0 ) {
2591 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status
));
2593 unumsys_close(unumsys
);
2595 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr
->locale
, myErrorName(status
));
2599 for (int i
=0; i
<3; ++i
) {
2600 // Run the test of unumsys_openAvailableNames() multiple times.
2601 // Helps verify the management of the internal cache of the names.
2602 status
= U_ZERO_ERROR
;
2603 uenum
= unumsys_openAvailableNames(&status
);
2604 if ( U_SUCCESS(status
) ) {
2605 int32_t numsysCount
= 0;
2606 // sanity check for a couple of number systems that must be in the enumeration
2607 UBool foundLatn
= FALSE
;
2608 UBool foundArab
= FALSE
;
2609 while ( (numsys
= uenum_next(uenum
, NULL
, &status
)) != NULL
&& U_SUCCESS(status
) ) {
2610 status
= U_ZERO_ERROR
;
2611 unumsys
= unumsys_openByName(numsys
, &status
);
2612 if ( U_SUCCESS(status
) ) {
2614 if ( uprv_strcmp(numsys
, "latn") ) foundLatn
= TRUE
;
2615 if ( uprv_strcmp(numsys
, "arab") ) foundArab
= TRUE
;
2616 unumsys_close(unumsys
);
2618 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2619 numsys
, myErrorName(status
));
2623 if ( numsysCount
< 40 || !foundLatn
|| !foundArab
) {
2624 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2625 numsysCount
, foundLatn
, foundArab
);
2628 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status
));
2633 /* plain-C version of test in numfmtst.cpp */
2634 enum { kUBufMax
= 64, kBBufMax
= 128 };
2635 static void TestCurrencyIsoPluralFormat(void) {
2636 static const char* DATA
[][8] = {
2639 // currency amount to be formatted,
2640 // currency ISO code to be formatted,
2641 // format result using CURRENCYSTYLE,
2642 // format result using CURRENCY_STANDARD,
2643 // format result using CURRENCY_ACCOUNTING,
2644 // format result using ISOCURRENCYSTYLE,
2645 // format result using PLURALCURRENCYSTYLE,
2647 // locale amount ISOcode CURRENCYSTYLE CURRENCY_STANDARD CURRENCY_ACCOUNTING ISOCURRENCYSTYLE PLURALCURRENCYSTYLE
2648 {"en_US", "1", "USD", "$1.00", "$1.00", "$1.00", "USD\\u00A01.00", "1.00 US dollars"},
2649 {"en_US", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD\\u00A01,234.56", "1,234.56 US dollars"},
2650 {"en_US@cf=account", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD\\u00A01,234.56", "1,234.56 US dollars"},
2651 {"en_US", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2652 {"en_US@cf=account", "-1234.56", "USD", "($1,234.56)", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2653 {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2654 {"zh_CN", "1", "USD", "US$1.00", "US$1.00", "US$1.00", "USD\\u00A01.00", "1.00\\u00A0\\u7F8E\\u5143"},
2655 {"zh_CN", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2656 {"zh_CN@cf=account", "-1", "USD", "(US$1.00)", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2657 {"zh_CN@cf=standard", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2658 {"zh_CN", "1234.56", "USD", "US$1,234.56", "US$1,234.56", "US$1,234.56", "USD\\u00A01,234.56", "1,234.56\\u00A0\\u7F8E\\u5143"},
2659 // {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "CHY1.00", "CHY1.00", "1.00 CHY"}, // wrong ISO code
2660 // {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, // wrong ISO code
2661 {"zh_CN", "1", "CNY", "\\u00A51.00", "\\u00A51.00", "\\u00A51.00", "CNY\\u00A01.00", "1.00\\u00A0\\u4EBA\\u6C11\\u5E01"},
2662 {"zh_CN", "1234.56", "CNY", "\\u00A51,234.56", "\\u00A51,234.56", "\\u00A51,234.56", "CNY\\u00A01,234.56", "1,234.56\\u00A0\\u4EBA\\u6C11\\u5E01"},
2663 {"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 "
2664 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2665 {"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 "
2666 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2667 {"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 "
2668 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2669 {"ja_JP", "42", NULL
, "\\u00A542", "\\u00A542", "\\u00A542", "JPY\\u00A042", "42\\u00A0\\u5186"},
2670 {"ja_JP@currency=USD", "42", NULL
, "$42.00", "$42.00", "$42.00", "USD\\u00A042.00", "42.00\\u00A0\\u7C73\\u30C9\\u30EB"},
2671 {"ms_MY", "1234.56", "MYR", "RM1,234.56", "RM1,234.56", "RM1,234.56", "MYR1,234.56", "1,234.56 Ringgit Malaysia"},
2672 {"id_ID", "1234.56", "IDR", "Rp1.235", "Rp1.235", "Rp1.235", "IDR\\u00A01.235", "1.235 Rupiah Indonesia"},
2673 // test locale without currency information
2674 {"root", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2675 {"root@cf=account", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2676 // test choice format
2677 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
2679 static const UNumberFormatStyle currencyStyles
[] = {
2681 UNUM_CURRENCY_STANDARD
,
2682 UNUM_CURRENCY_ACCOUNTING
,
2684 UNUM_CURRENCY_PLURAL
2689 for (i
=0; i
<UPRV_LENGTHOF(DATA
); ++i
) {
2690 const char* localeString
= DATA
[i
][0];
2691 double numberToBeFormat
= atof(DATA
[i
][1]);
2692 const char* currencyISOCode
= DATA
[i
][2];
2693 for (sIndex
= 0; sIndex
< UPRV_LENGTHOF(currencyStyles
); ++sIndex
) {
2694 UNumberFormatStyle style
= currencyStyles
[sIndex
];
2695 UErrorCode status
= U_ZERO_ERROR
;
2696 UChar currencyCode
[4] = {0};
2697 UChar ubufResult
[kUBufMax
];
2698 UChar ubufExpected
[kUBufMax
];
2700 const char* currencyISOCodeForLog
= currencyISOCode
;
2702 UNumberFormat
* unumFmt
= unum_open(style
, NULL
, 0, localeString
, NULL
, &status
);
2703 if (U_FAILURE(status
)) {
2704 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString
, (int)style
, myErrorName(status
));
2707 if (currencyISOCode
!= NULL
) {
2708 u_charsToUChars(currencyISOCode
, currencyCode
, 4);
2709 unum_setTextAttribute(unumFmt
, UNUM_CURRENCY_CODE
, currencyCode
, 3, &status
);
2711 unum_setTextAttribute(unumFmt
, UNUM_CURRENCY_CODE
, NULL
, 0, &status
);
2712 currencyISOCodeForLog
= "(null)";
2714 if (U_FAILURE(status
)) {
2715 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString
, currencyISOCodeForLog
, myErrorName(status
));
2717 ulenRes
= unum_formatDouble(unumFmt
, numberToBeFormat
, ubufResult
, kUBufMax
, NULL
, &status
);
2718 if (U_FAILURE(status
)) {
2719 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString
, currencyISOCodeForLog
, myErrorName(status
));
2721 int32_t ulenExp
= u_unescape(DATA
[i
][3 + sIndex
], ubufExpected
, kUBufMax
);
2722 if (ulenRes
!= ulenExp
|| u_strncmp(ubufResult
, ubufExpected
, ulenExp
) != 0) {
2723 char bbufExpected
[kBBufMax
];
2724 char bbufResult
[kBBufMax
];
2725 u_strToUTF8(bbufExpected
, kBBufMax
, NULL
, ubufExpected
, ulenExp
, &status
);
2726 u_strToUTF8(bbufResult
, kBBufMax
, NULL
, ubufResult
, ulenRes
, &status
);
2727 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got %s\n",
2728 localeString
, currencyISOCodeForLog
, bbufExpected
, bbufResult
);
2731 unum_close(unumFmt
);
2737 const char * locale
;
2738 UNumberFormatStyle style
;
2739 UDisplayContext context
;
2740 const char * expectedResult
;
2743 /* currently no locales have contextTransforms data for "symbol" type */
2744 static const TestContextItem tcItems
[] = { /* results for 123.45 */
2745 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2746 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2747 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2748 { "sv", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2749 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE
, "one hundred twenty-three point four five" },
2750 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
, "One hundred twenty-three point four five" },
2751 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
, "One hundred twenty-three point four five" },
2752 { "en", UNUM_SPELLOUT
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, "One hundred twenty-three point four five" },
2753 { NULL
, (UNumberFormatStyle
)0, (UDisplayContext
)0, NULL
}
2756 static void TestContext(void) {
2757 UErrorCode status
= U_ZERO_ERROR
;
2758 const TestContextItem
* itemPtr
;
2760 UNumberFormat
*unum
= unum_open(UNUM_SPELLOUT
, NULL
, 0, "en", NULL
, &status
);
2761 if ( U_SUCCESS(status
) ) {
2762 UDisplayContext context
= unum_getContext(unum
, UDISPCTX_TYPE_CAPITALIZATION
, &status
);
2763 if ( U_FAILURE(status
) || context
!= UDISPCTX_CAPITALIZATION_NONE
) {
2764 log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n");
2765 status
= U_ZERO_ERROR
;
2767 unum_setContext(unum
, UDISPCTX_CAPITALIZATION_FOR_STANDALONE
, &status
);
2768 context
= unum_getContext(unum
, UDISPCTX_TYPE_CAPITALIZATION
, &status
);
2769 if ( U_FAILURE(status
) || context
!= UDISPCTX_CAPITALIZATION_FOR_STANDALONE
) {
2770 log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n");
2774 log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status
));
2776 #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION
2777 for (itemPtr
= tcItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
2778 UChar ubufResult
[kUBufMax
];
2781 status
= U_ZERO_ERROR
;
2782 unum
= unum_open(itemPtr
->style
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
2783 if (U_FAILURE(status
)) {
2784 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2785 itemPtr
->locale
, (int)itemPtr
->style
, myErrorName(status
));
2788 unum_setContext(unum
, itemPtr
->context
, &status
);
2789 ulenRes
= unum_formatDouble(unum
, 123.45, ubufResult
, kUBufMax
, NULL
, &status
);
2790 if (U_FAILURE(status
)) {
2791 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
2792 itemPtr
->locale
, (int)itemPtr
->style
, (int)itemPtr
->context
, myErrorName(status
));
2794 UChar ubufExpected
[kUBufMax
];
2795 int32_t ulenExp
= u_unescape(itemPtr
->expectedResult
, ubufExpected
, kUBufMax
);
2796 if (ulenRes
!= ulenExp
|| u_strncmp(ubufResult
, ubufExpected
, ulenExp
) != 0) {
2797 char bbuf
[kUBufMax
*2];
2798 u_austrncpy(bbuf
, ubufResult
, sizeof(bbuf
));
2799 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
2800 itemPtr
->locale
, (int)itemPtr
->style
, (int)itemPtr
->context
, ulenExp
,
2801 itemPtr
->expectedResult
, ulenRes
, bbuf
);
2806 #endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */
2809 static void TestCurrencyUsage(void) {
2810 static const char* DATA
[][2] = {
2812 * currency ISO code to be formatted,
2813 * format result using CURRENCYSTYLE with CASH purpose,-
2814 * Note that as of CLDR 26:-
2815 * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
2816 * - CAD rounds to .05
2819 {"PKR", "PKR\\u00A0124"},
2820 {"CAD", "CA$123.55"},
2824 // 1st time for getter/setter, 2nd for factory method
2827 const char* localeString
= "en_US";
2828 double numberToBeFormat
= 123.567;
2829 UNumberFormat
* unumFmt
;
2830 UNumberFormatStyle style
= UNUM_CURRENCY
;
2831 UErrorCode status
= U_ZERO_ERROR
;
2834 if(i
== 1){ // change for factory method
2835 style
= UNUM_CASH_CURRENCY
;
2838 unumFmt
= unum_open(style
, NULL
, 0, localeString
, NULL
, &status
);
2839 if (U_FAILURE(status
)) {
2840 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2841 localeString
, (int)style
, myErrorName(status
));
2845 if(i
== 0){ // this is for the getter/setter
2846 if(unum_getAttribute(unumFmt
, UNUM_CURRENCY_USAGE
) != UCURR_USAGE_STANDARD
) {
2847 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n");
2850 unum_setAttribute(unumFmt
, UNUM_CURRENCY_USAGE
, UCURR_USAGE_CASH
);
2853 if(unum_getAttribute(unumFmt
, UNUM_CURRENCY_USAGE
) != UCURR_USAGE_CASH
) {
2854 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n");
2857 for (j
=0; j
<UPRV_LENGTHOF(DATA
); ++j
) {
2860 UChar currencyCode
[4];
2863 UFieldPosition pos
= {0};
2865 u_charsToUChars(DATA
[j
][0], currencyCode
, 3);
2866 expectLen
= u_unescape(DATA
[j
][1], expect
, UPRV_LENGTHOF(expect
));
2868 unum_setTextAttribute(unumFmt
, UNUM_CURRENCY_CODE
, currencyCode
, 3, &status
);
2869 assertSuccess("num_setTextAttribute()", &status
);
2871 resultLen
= unum_formatDouble(unumFmt
, numberToBeFormat
, result
, UPRV_LENGTHOF(result
),
2873 assertSuccess("num_formatDouble()", &status
);
2875 if(resultLen
!= expectLen
|| u_strcmp(result
, expect
) != 0) {
2876 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n",
2877 aescstrdup(expect
, expectLen
), aescstrdup(result
, resultLen
));
2882 unum_close(unumFmt
);
2886 static UChar currFmtNegSameAsPos
[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */
2887 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2889 // NOTE: As of ICU 62, identical positive and negative subpatterns means no minus sign!
2890 // See CLDR ticket https://unicode.org/cldr/trac/ticket/10703
2891 //static UChar currFmtToPatExpected[] = /* "\u00A4#,##0.00" */
2892 // {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2893 static const UChar
* currFmtToPatExpected
= currFmtNegSameAsPos
;
2895 static UChar currFmtResultExpected
[] = /* "$100.00" */
2896 {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0};
2898 static UChar emptyString
[] = {0};
2900 enum { kUBufSize
= 64, kBBufSize
= 128 };
2902 static void TestCurrFmtNegSameAsPositive(void) {
2903 UErrorCode status
= U_ZERO_ERROR
;
2904 UNumberFormat
* unumfmt
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
2905 if ( U_SUCCESS(status
) ) {
2906 unum_applyPattern(unumfmt
, FALSE
, currFmtNegSameAsPos
, -1, NULL
, &status
);
2907 if (U_SUCCESS(status
)) {
2908 UChar ubuf
[kUBufSize
];
2909 int32_t ulen
= unum_toPattern(unumfmt
, FALSE
, ubuf
, kUBufSize
, &status
);
2910 if (U_FAILURE(status
)) {
2911 log_err("unum_toPattern fails with status %s\n", myErrorName(status
));
2912 } else if (u_strcmp(ubuf
, currFmtToPatExpected
) != 0) {
2913 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected
,-1), aescstrdup(ubuf
,ulen
));
2915 unum_setSymbol(unumfmt
, UNUM_MINUS_SIGN_SYMBOL
, emptyString
, 0, &status
);
2916 if (U_SUCCESS(status
)) {
2917 ulen
= unum_formatDouble(unumfmt
, -100.0, ubuf
, kUBufSize
, NULL
, &status
);
2918 if (U_FAILURE(status
)) {
2919 log_err("unum_formatDouble fails with status %s\n", myErrorName(status
));
2920 } else if (u_strcmp(ubuf
, currFmtResultExpected
) != 0) {
2921 log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected
,-1), aescstrdup(ubuf
,ulen
));
2924 log_err("unum_setSymbol fails with status %s\n", myErrorName(status
));
2927 log_err("unum_applyPattern fails with status %s\n", myErrorName(status
));
2929 unum_close(unumfmt
);
2931 log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status
));
2938 const char *valueStr
;
2939 const char *expected
;
2940 } ValueAndExpectedString
;
2942 static const ValueAndExpectedString enDecMinFrac
[] = {
2943 {0.0, "0.0", "0.0"},
2944 {0.17, "0.17", "0.17"},
2945 {1.0, "1.0", "1.0"},
2946 {1234.0, "1234.0", "1,234.0"},
2947 {12345.0, "12345.0", "12,345.0"},
2948 {123456.0, "123456.0", "123,456.0"},
2949 {1234567.0, "1234567.0", "1,234,567.0"},
2950 {12345678.0, "12345678.0", "12,345,678.0"},
2953 static const ValueAndExpectedString enShort
[] = {
2955 {0.17, "0.17", "0.17"},
2957 {1234.0, "1234.0", "1.2K"},
2958 {12345.0, "12345.0", "12K"},
2959 {123456.0, "123456.0", "123K"},
2960 {1234567.0, "1234567.0", "1.2M"},
2961 {12345678.0, "12345678.0", "12M"},
2962 {123456789.0, "123456789.0", "123M"},
2963 {1.23456789E9
, "1.23456789E9", "1.2B"},
2964 {1.23456789E10
, "1.23456789E10", "12B"},
2965 {1.23456789E11
, "1.23456789E11", "123B"},
2966 {1.23456789E12
, "1.23456789E12", "1.2T"},
2967 {1.23456789E13
, "1.23456789E13", "12T"},
2968 {1.23456789E14
, "1.23456789E14", "123T"},
2969 {1.23456789E15
, "1.23456789E15", "1235T"},
2973 static const ValueAndExpectedString enShortMax2
[] = {
2975 {0.17, "0.17", "0.17"},
2977 {1234.0, "1234.0", "1.2K"},
2978 {12345.0, "12345.0", "12K"},
2979 {123456.0, "123456.0", "120K"},
2980 {1234567.0, "1234567.0", "1.2M"},
2981 {12345678.0, "12345678.0", "12M"},
2982 {123456789.0, "123456789.0", "120M"},
2983 {1.23456789E9
, "1.23456789E9", "1.2B"},
2984 {1.23456789E10
, "1.23456789E10", "12B"},
2985 {1.23456789E11
, "1.23456789E11", "120B"},
2986 {1.23456789E12
, "1.23456789E12", "1.2T"},
2987 {1.23456789E13
, "1.23456789E13", "12T"},
2988 {1.23456789E14
, "1.23456789E14", "120T"},
2989 {1.23456789E15
, "1.23456789E15", "1200T"},
2993 static const ValueAndExpectedString enShortMax5
[] = {
2995 {0.17, "0.17", "0.17"},
2997 {1234.0, "1234.0", "1.234K"},
2998 {12345.0, "12345.0", "12.345K"},
2999 {123456.0, "123456.0", "123.46K"},
3000 {1234567.0, "1234567.0", "1.2346M"},
3001 {12345678.0, "12345678.0", "12.346M"},
3002 {123456789.0, "123456789.0", "123.46M"},
3003 {1.23456789E9
, "1.23456789E9", "1.2346B"},
3004 {1.23456789E10
, "1.23456789E10", "12.346B"},
3005 {1.23456789E11
, "1.23456789E11", "123.46B"},
3006 {1.23456789E12
, "1.23456789E12", "1.2346T"},
3007 {1.23456789E13
, "1.23456789E13", "12.346T"},
3008 {1.23456789E14
, "1.23456789E14", "123.46T"},
3009 {1.23456789E15
, "1.23456789E15", "1234.6T"},
3013 static const ValueAndExpectedString enShortMin3
[] = {
3014 {0.0, "0.0", "0.00"},
3015 {0.17, "0.17", "0.170"},
3016 {1.0, "1.0", "1.00"},
3017 {1234.0, "1234.0", "1.23K"},
3018 {12345.0, "12345.0", "12.3K"},
3019 {123456.0, "123456.0", "123K"},
3020 {1234567.0, "1234567.0", "1.23M"},
3021 {12345678.0, "12345678.0", "12.3M"},
3022 {123456789.0, "123456789.0", "123M"},
3023 {1.23456789E9
, "1.23456789E9", "1.23B"},
3024 {1.23456789E10
, "1.23456789E10", "12.3B"},
3025 {1.23456789E11
, "1.23456789E11", "123B"},
3026 {1.23456789E12
, "1.23456789E12", "1.23T"},
3027 {1.23456789E13
, "1.23456789E13", "12.3T"},
3028 {1.23456789E14
, "1.23456789E14", "123T"},
3029 {1.23456789E15
, "1.23456789E15", "1230T"},
3033 static const ValueAndExpectedString jaShortMax2
[] = {
3034 {1234.0, "1234.0", "1200"},
3035 {12345.0, "12345.0", "1.2\\u4E07"},
3036 {123456.0, "123456.0", "12\\u4E07"},
3037 {1234567.0, "1234567.0", "120\\u4E07"},
3038 {12345678.0, "12345678.0", "1200\\u4E07"},
3039 {123456789.0, "123456789.0", "1.2\\u5104"},
3040 {1.23456789E9
, "1.23456789E9", "12\\u5104"},
3041 {1.23456789E10
, "1.23456789E10", "120\\u5104"},
3042 {1.23456789E11
, "1.23456789E11", "1200\\u5104"},
3043 {1.23456789E12
, "1.23456789E12", "1.2\\u5146"},
3044 {1.23456789E13
, "1.23456789E13", "12\\u5146"},
3045 {1.23456789E14
, "1.23456789E14", "120\\u5146"},
3049 static const ValueAndExpectedString srLongMax2
[] = {
3050 {1234.0, "1234.0", "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
3051 {12345.0, "12345.0", "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
3052 {21789.0, "21789.0", "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
3053 {123456.0, "123456.0", "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
3054 {999999.0, "999999.0", "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
3055 {1234567.0, "1234567.0", "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
3056 {12345678.0, "12345678.0", "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
3057 {123456789.0, "123456789.0", "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
3058 {1.23456789E9
, "1.23456789E9", "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
3059 {1.23456789E10
, "1.23456789E10", "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
3060 {2.08901234E10
, "2.08901234E10", "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
3061 {2.18901234E10
, "2.18901234E10", "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
3062 {1.23456789E11
, "1.23456789E11", "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
3063 {-1234.0, "-1234.0", "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
3064 {-12345.0, "-12345.0", "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
3065 {-21789.0, "-21789.0", "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
3066 {-123456.0, "-123456.0", "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
3067 {-999999.0, "-999999.0", "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
3068 {-1234567.0, "-1234567.0", "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3069 {-12345678.0, "-12345678.0", "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3070 {-123456789.0, "-123456789.0", "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3071 {-1.23456789E9
, "-1.23456789E9", "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
3072 {-1.23456789E10
, "-1.23456789E10", "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
3073 {-2.08901234E10
, "-2.08901234E10", "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
3074 {-2.18901234E10
, "-2.18901234E10", "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
3075 {-1.23456789E11
, "-1.23456789E11", "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
3080 const char * locale
;
3081 UNumberFormatStyle style
;
3082 int32_t attribute
; // UNumberFormatAttribute, or -1 for none
3083 int32_t attrValue
; //
3084 const ValueAndExpectedString
* veItems
;
3085 } LocStyleAttributeTest
;
3087 static const LocStyleAttributeTest lsaTests
[] = {
3088 { "en", UNUM_DECIMAL
, UNUM_MIN_FRACTION_DIGITS
, 1, enDecMinFrac
},
3089 { "en", UNUM_DECIMAL_COMPACT_SHORT
, -1, 0, enShort
},
3090 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, enShortMax2
},
3091 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 5, enShortMax5
},
3092 { "en", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MIN_SIGNIFICANT_DIGITS
, 3, enShortMin3
},
3093 { "ja", UNUM_DECIMAL_COMPACT_SHORT
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, jaShortMax2
},
3094 { "sr", UNUM_DECIMAL_COMPACT_LONG
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2, srLongMax2
},
3095 { NULL
, (UNumberFormatStyle
)0, -1, 0, NULL
}
3098 static void TestVariousStylesAndAttributes(void) {
3099 const LocStyleAttributeTest
* lsaTestPtr
;
3100 for (lsaTestPtr
= lsaTests
; lsaTestPtr
->locale
!= NULL
; lsaTestPtr
++) {
3101 UErrorCode status
= U_ZERO_ERROR
;
3102 UNumberFormat
* unum
= unum_open(lsaTestPtr
->style
, NULL
, 0, lsaTestPtr
->locale
, NULL
, &status
);
3103 if ( U_FAILURE(status
) ) {
3104 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, u_errorName(status
));
3106 const ValueAndExpectedString
* veItemPtr
;
3107 if (lsaTestPtr
->attribute
>= 0) {
3108 unum_setAttribute(unum
, (UNumberFormatAttribute
)lsaTestPtr
->attribute
, lsaTestPtr
->attrValue
);
3110 // ICU 62: should call minSignificantDigits in tandem with maxSignificantDigits.
3111 if (lsaTestPtr
->attribute
== UNUM_MIN_SIGNIFICANT_DIGITS
) {
3112 unum_setAttribute(unum
, UNUM_MAX_SIGNIFICANT_DIGITS
, lsaTestPtr
->attrValue
);
3114 for (veItemPtr
= lsaTestPtr
->veItems
; veItemPtr
->expected
!= NULL
; veItemPtr
++) {
3115 UChar uexp
[kUBufSize
];
3116 UChar uget
[kUBufSize
];
3117 int32_t uexplen
, ugetlen
;
3119 status
= U_ZERO_ERROR
;
3120 uexplen
= u_unescape(veItemPtr
->expected
, uexp
, kUBufSize
);
3121 ugetlen
= unum_formatDouble(unum
, veItemPtr
->value
, uget
, kUBufSize
, NULL
, &status
);
3122 if ( U_FAILURE(status
) ) {
3123 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n",
3124 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->value
, u_errorName(status
));
3125 } else if (ugetlen
!= uexplen
|| u_strncmp(uget
, uexp
, uexplen
) != 0) {
3126 char bexp
[kBBufSize
];
3127 char bget
[kBBufSize
];
3128 u_strToUTF8(bexp
, kBBufSize
, NULL
, uexp
, uexplen
, &status
);
3129 u_strToUTF8(bget
, kBBufSize
, NULL
, uget
, ugetlen
, &status
);
3130 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n",
3131 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->value
, bexp
, bget
);
3133 status
= U_ZERO_ERROR
;
3134 ugetlen
= unum_formatDecimal(unum
, veItemPtr
->valueStr
, -1, uget
, kUBufSize
, NULL
, &status
);
3135 if ( U_FAILURE(status
) ) {
3136 log_err("FAIL: unum_formatDecimal style %d, locale %s, attr %d, valueStr %s: error %s\n",
3137 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->valueStr
, u_errorName(status
));
3138 } else if (ugetlen
!= uexplen
|| u_strncmp(uget
, uexp
, uexplen
) != 0) {
3139 char bexp
[kBBufSize
];
3140 char bget
[kBBufSize
];
3141 u_strToUTF8(bexp
, kBBufSize
, NULL
, uexp
, uexplen
, &status
);
3142 u_strToUTF8(bget
, kBBufSize
, NULL
, uget
, ugetlen
, &status
);
3143 log_err("FAIL: unum_formatDecimal style %d, locale %s, attr %d, valueStr %s: expect \"%s\", get \"%s\"\n",
3144 (int)lsaTestPtr
->style
, lsaTestPtr
->locale
, lsaTestPtr
->attribute
, veItemPtr
->valueStr
, bexp
, bget
);
3152 static const UChar currpat
[] = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; /* ¤#,##0.00 */
3153 static const UChar parsetxt
[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */
3155 static void TestParseCurrPatternWithDecStyle() {
3156 UErrorCode status
= U_ZERO_ERROR
;
3157 UNumberFormat
*unumfmt
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
3158 if (U_FAILURE(status
)) {
3159 log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status
));
3161 unum_applyPattern(unumfmt
, FALSE
, currpat
, -1, NULL
, &status
);
3162 if (U_FAILURE(status
)) {
3163 log_err_status(status
, "unum_applyPattern failed: %s\n", u_errorName(status
));
3166 double value
= unum_parseDouble(unumfmt
, parsetxt
, -1, &pos
, &status
);
3167 if (U_SUCCESS(status
)) {
3168 log_err_status(status
, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status
), value
);
3171 unum_close(unumfmt
);
3177 * Test unum_formatDoubleForFields (and UFieldPositionIterator)
3187 const char * locale
;
3188 UNumberFormatStyle style
;
3190 const FieldsData
* expectedFields
;
3191 } FormatForFieldsItem
;
3193 static const UChar patNoFields
[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
3196 /* "en_US", UNUM_CURRENCY, 123456.0 : "¤#,##0.00" => "$123,456.00" */
3197 static const FieldsData fields_en_CURR
[] = {
3198 { UNUM_CURRENCY_FIELD
/*7*/, 0, 1 },
3199 { UNUM_GROUPING_SEPARATOR_FIELD
/*6*/, 4, 5 },
3200 { UNUM_INTEGER_FIELD
/*0*/, 1, 8 },
3201 { UNUM_DECIMAL_SEPARATOR_FIELD
/*2*/, 8, 9 },
3202 { UNUM_FRACTION_FIELD
/*1*/, 9, 11 },
3205 /* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
3206 static const FieldsData fields_en_PRCT
[] = {
3207 { UNUM_SIGN_FIELD
/*10*/, 0, 1 },
3208 { UNUM_INTEGER_FIELD
/*0*/, 1, 3 },
3209 { UNUM_PERCENT_FIELD
/*8*/, 3, 4 },
3212 /* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00 ¤" => "123,456.00 €" */
3213 static const FieldsData fields_fr_CURR
[] = {
3214 { UNUM_GROUPING_SEPARATOR_FIELD
/*6*/, 3, 4 },
3215 { UNUM_INTEGER_FIELD
/*0*/, 0, 7 },
3216 { UNUM_DECIMAL_SEPARATOR_FIELD
/*2*/, 7, 8 },
3217 { UNUM_FRACTION_FIELD
/*1*/, 8, 10 },
3218 { UNUM_CURRENCY_FIELD
/*7*/, 11, 12 },
3221 /* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
3222 static const FieldsData fields_en_PATN
[] = {
3223 { UNUM_INTEGER_FIELD
/*0*/, 1, 3 },
3227 static const FormatForFieldsItem fffItems
[] = {
3228 { "en_US", UNUM_CURRENCY_STANDARD
, 123456.0, fields_en_CURR
},
3229 { "en_US", UNUM_PERCENT
, -0.34, fields_en_PRCT
},
3230 { "fr_FR", UNUM_CURRENCY_STANDARD
, 123456.0, fields_fr_CURR
},
3231 { "en_US", UNUM_PATTERN_DECIMAL
, 12.0, fields_en_PATN
},
3232 { NULL
, (UNumberFormatStyle
)0, 0, NULL
},
3235 static void TestFormatForFields(void) {
3236 UErrorCode status
= U_ZERO_ERROR
;
3237 UFieldPositionIterator
* fpositer
= ufieldpositer_open(&status
);
3238 if ( U_FAILURE(status
) ) {
3239 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status
));
3241 const FormatForFieldsItem
* itemPtr
;
3242 for (itemPtr
= fffItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3243 UNumberFormat
* unum
;
3244 status
= U_ZERO_ERROR
;
3245 unum
= (itemPtr
->style
== UNUM_PATTERN_DECIMAL
)?
3246 unum_open(itemPtr
->style
, patNoFields
, -1, itemPtr
->locale
, NULL
, &status
):
3247 unum_open(itemPtr
->style
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3248 if ( U_FAILURE(status
) ) {
3249 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
));
3251 UChar ubuf
[kUBufSize
];
3252 int32_t ulen
= unum_formatDoubleForFields(unum
, itemPtr
->value
, ubuf
, kUBufSize
, fpositer
, &status
);
3253 if ( U_FAILURE(status
) ) {
3254 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr
->locale
, itemPtr
->style
, u_errorName(status
));
3256 const FieldsData
* fptr
;
3257 int32_t field
, beginPos
, endPos
;
3258 for (fptr
= itemPtr
->expectedFields
; TRUE
; fptr
++) {
3259 field
= ufieldpositer_next(fpositer
, &beginPos
, &endPos
);
3260 if (field
!= fptr
->field
|| (field
>= 0 && (beginPos
!= fptr
->beginPos
|| endPos
!= fptr
->endPos
))) {
3261 if (fptr
->field
>= 0) {
3262 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
3263 itemPtr
->locale
, aescstrdup(ubuf
, ulen
), fptr
->field
, fptr
->beginPos
, fptr
->endPos
, field
, beginPos
, endPos
);
3265 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
3266 itemPtr
->locale
, aescstrdup(ubuf
, ulen
), field
, beginPos
, endPos
);
3278 ufieldpositer_close(fpositer
);
3282 static void Test12052_NullPointer() {
3283 UErrorCode status
= U_ZERO_ERROR
;
3284 static const UChar input
[] = u
"199a";
3285 UChar currency
[200] = {0};
3286 UNumberFormat
*theFormatter
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
3287 if (!assertSuccessCheck("unum_open() failed", &status
, TRUE
)) { return; }
3288 status
= U_ZERO_ERROR
;
3289 unum_setAttribute(theFormatter
, UNUM_LENIENT_PARSE
, 1);
3291 unum_parseDoubleCurrency(theFormatter
, input
, -1, &pos
, currency
, &status
);
3292 assertEquals("should fail gracefully", "U_PARSE_ERROR", u_errorName(status
));
3293 unum_close(theFormatter
);
3298 const UChar
* text
; // text to parse
3299 UBool lenient
; // leniency to use
3300 UBool intOnly
; // whether to set PARSE_INT_ONLY
3301 UErrorCode intStatus
; // expected status from parse
3302 int32_t intPos
; // expected final pos from parse
3303 int32_t intValue
; // expected value from parse
3304 UErrorCode doubStatus
; // expected status from parseDouble
3305 int32_t doubPos
; // expected final pos from parseDouble
3306 double doubValue
; // expected value from parseDouble
3307 UErrorCode decStatus
; // expected status from parseDecimal
3308 int32_t decPos
; // expected final pos from parseDecimal
3309 const char* decString
; // expected output string from parseDecimal
3313 static const ParseCaseItem parseCaseItems
[] = {
3314 { "en", u
"0,000", FALSE
, FALSE
, U_ZERO_ERROR
, 5, 0, U_ZERO_ERROR
, 5, 0.0, U_ZERO_ERROR
, 5, "0" },
3315 { "en", u
"0,000", TRUE
, FALSE
, U_ZERO_ERROR
, 5, 0, U_ZERO_ERROR
, 5, 0.0, U_ZERO_ERROR
, 5, "0" },
3316 { "en", u
",024", FALSE
, FALSE
, U_ZERO_ERROR
, 4, 24, U_ZERO_ERROR
, 4, 24.0, U_ZERO_ERROR
, 4, "24" },
3317 { "en", u
",024", TRUE
, FALSE
, U_ZERO_ERROR
, 4, 24, U_ZERO_ERROR
, 4, 24.0, U_ZERO_ERROR
, 4, "24" },
3318 { "en", u
"1000,000", FALSE
, FALSE
, U_PARSE_ERROR
, 0, 0, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, "" },
3319 { "en", u
"1000,000", TRUE
, FALSE
, U_ZERO_ERROR
, 8, 1000000, U_ZERO_ERROR
, 8, 1000000.0, U_ZERO_ERROR
, 8, "1000000" },
3320 { "en", u
"", FALSE
, FALSE
, U_PARSE_ERROR
, 0, 0, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, "" },
3321 { "en", u
"", TRUE
, FALSE
, U_PARSE_ERROR
, 0, 0, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, "" },
3322 { "en", u
"9999990000503021", FALSE
, FALSE
, U_INVALID_FORMAT_ERROR
, 16, 2147483647, U_ZERO_ERROR
, 16, 9999990000503020.0, U_ZERO_ERROR
, 16, "9999990000503021" },
3323 { "en", u
"9999990000503021", FALSE
, TRUE
, U_INVALID_FORMAT_ERROR
, 16, 2147483647, U_ZERO_ERROR
, 16, 9999990000503020.0, U_ZERO_ERROR
, 16, "9999990000503021" },
3324 { "en", u
"1000000.5", FALSE
, FALSE
, U_ZERO_ERROR
, 9, 1000000, U_ZERO_ERROR
, 9, 1000000.5, U_ZERO_ERROR
, 9, "1.0000005E+6" /* change from ICU-62nnn */},
3325 { "en", u
"1000000.5", FALSE
, TRUE
, U_ZERO_ERROR
, 7, 1000000, U_ZERO_ERROR
, 7, 1000000.0, U_ZERO_ERROR
, 7, "1000000" },
3326 { "en", u
"123.5", FALSE
, FALSE
, U_ZERO_ERROR
, 5, 123, U_ZERO_ERROR
, 5, 123.5, U_ZERO_ERROR
, 5, "123.5" },
3327 { "en", u
"123.5", FALSE
, TRUE
, U_ZERO_ERROR
, 3, 123, U_ZERO_ERROR
, 3, 123.0, U_ZERO_ERROR
, 3, "123" },
3328 { NULL
, NULL
, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, NULL
}
3331 static void TestParseCases(void) {
3332 const ParseCaseItem
* itemPtr
;
3333 for (itemPtr
= parseCaseItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3334 UErrorCode status
= U_ZERO_ERROR
;
3335 UNumberFormat
* unumDec
= unum_open(UNUM_DECIMAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3336 if (U_FAILURE(status
)) {
3337 log_data_err("unum_open UNUM_DECIMAL fails for locale %s: %s\n", itemPtr
->locale
, u_errorName(status
));
3340 int32_t intValue
, parsePos
, dclen
;
3343 unum_setAttribute(unumDec
, UNUM_LENIENT_PARSE
, itemPtr
->lenient
);
3344 unum_setAttribute(unumDec
, UNUM_PARSE_INT_ONLY
, itemPtr
->intOnly
);
3347 status
= U_ZERO_ERROR
;
3348 intValue
= unum_parse(unumDec
, itemPtr
->text
, -1, &parsePos
, &status
);
3349 if (status
!= itemPtr
->intStatus
|| parsePos
!= itemPtr
->intPos
|| intValue
!= itemPtr
->intValue
) {
3351 u_austrcpy(btext
, itemPtr
->text
);
3352 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parse expected status %s, pos %d, value %d;\n got %s, %d, %d\n",
3353 itemPtr
->locale
, btext
, itemPtr
->lenient
, itemPtr
->intOnly
,
3354 u_errorName(itemPtr
->intStatus
), itemPtr
->intPos
, itemPtr
->intValue
,
3355 u_errorName(status
), parsePos
, intValue
);
3359 status
= U_ZERO_ERROR
;
3360 doubValue
= unum_parseDouble(unumDec
, itemPtr
->text
, -1, &parsePos
, &status
);
3361 if (status
!= itemPtr
->doubStatus
|| parsePos
!= itemPtr
->doubPos
|| doubValue
!= itemPtr
->doubValue
) {
3363 u_austrcpy(btext
, itemPtr
->text
);
3364 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parseDouble expected status %s, pos %d, value %.1f;\n got %s, %d, %.1f\n",
3365 itemPtr
->locale
, btext
, itemPtr
->lenient
, itemPtr
->intOnly
,
3366 u_errorName(itemPtr
->doubStatus
), itemPtr
->doubPos
, itemPtr
->doubValue
,
3367 u_errorName(status
), parsePos
, doubValue
);
3371 status
= U_ZERO_ERROR
;
3373 dclen
= unum_parseDecimal(unumDec
, itemPtr
->text
, -1, &parsePos
, decstr
, 32, &status
);
3374 if (status
!= itemPtr
->decStatus
|| parsePos
!= itemPtr
->decPos
|| uprv_strcmp(decstr
,itemPtr
->decString
) != 0) {
3376 u_austrcpy(btext
, itemPtr
->text
);
3377 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parseDecimal expected status %s, pos %d, str \"%s\";\n got %s, %d, \"%s\"\n",
3378 itemPtr
->locale
, btext
, itemPtr
->lenient
, itemPtr
->intOnly
,
3379 u_errorName(itemPtr
->decStatus
), itemPtr
->decPos
, itemPtr
->decString
,
3380 u_errorName(status
), parsePos
, decstr
);
3383 unum_close(unumDec
);
3388 const char* descrip
;
3390 UNumberFormatStyle style
;
3395 const UChar
* expPattern
;
3397 const UChar
* expFormat
;
3398 } SetMaxFracAndRoundIncrItem
;
3400 static const SetMaxFracAndRoundIncrItem maxFracAndRoundIncrItems
[] = {
3401 // descrip locale style mnI mnF mxF rdInc expPat value expFmt
3402 { "01 en_US DEC 1/0/3/0.0", "en_US", UNUM_DECIMAL
, 1, 0, 3, 0.0, u
"#,##0.###", 0.128, u
"0.128" },
3403 { "02 en_US DEC 1/0/1/0.0", "en_US", UNUM_DECIMAL
, 1, 0, 1, 0.0, u
"#,##0.#", 0.128, u
"0.1" },
3404 { "03 en_US DEC 1/0/1/0.01", "en_US", UNUM_DECIMAL
, 1, 0, 1, 0.01, u
"#,##0.#", 0.128, u
"0.1" },
3405 { "04 en_US DEC 1/1/1/0.01", "en_US", UNUM_DECIMAL
, 1, 1, 1, 0.01, u
"#,##0.0", 0.128, u
"0.1" },
3406 { "05 en_US DEC 1/0/1/0.1", "en_US", UNUM_DECIMAL
, 1, 0, 1, 0.1, u
"#,##0.1", 0.128, u
"0.1" }, // use incr
3407 { "06 en_US DEC 1/1/1/0.1", "en_US", UNUM_DECIMAL
, 1, 1, 1, 0.1, u
"#,##0.1", 0.128, u
"0.1" }, // use incr
3409 { "10 en_US DEC 1/0/1/0.02", "en_US", UNUM_DECIMAL
, 1, 0, 1, 0.02, u
"#,##0.#", 0.128, u
"0.1" },
3410 { "11 en_US DEC 1/0/2/0.02", "en_US", UNUM_DECIMAL
, 1, 0, 2, 0.02, u
"#,##0.02", 0.128, u
"0.12" }, // use incr
3411 { "12 en_US DEC 1/0/3/0.02", "en_US", UNUM_DECIMAL
, 1, 0, 3, 0.02, u
"#,##0.02#", 0.128, u
"0.12" }, // use incr
3412 { "13 en_US DEC 1/1/1/0.02", "en_US", UNUM_DECIMAL
, 1, 1, 1, 0.02, u
"#,##0.0", 0.128, u
"0.1" },
3413 { "14 en_US DEC 1/1/2/0.02", "en_US", UNUM_DECIMAL
, 1, 1, 2, 0.02, u
"#,##0.02", 0.128, u
"0.12" }, // use incr
3414 { "15 en_US DEC 1/1/3/0.02", "en_US", UNUM_DECIMAL
, 1, 1, 3, 0.02, u
"#,##0.02#", 0.128, u
"0.12" }, // use incr
3415 { "16 en_US DEC 1/2/2/0.02", "en_US", UNUM_DECIMAL
, 1, 2, 2, 0.02, u
"#,##0.02", 0.128, u
"0.12" }, // use incr
3416 { "17 en_US DEC 1/2/3/0.02", "en_US", UNUM_DECIMAL
, 1, 2, 3, 0.02, u
"#,##0.02#", 0.128, u
"0.12" }, // use incr
3417 { "18 en_US DEC 1/3/3/0.02", "en_US", UNUM_DECIMAL
, 1, 3, 3, 0.02, u
"#,##0.020", 0.128, u
"0.120" }, // use incr
3419 { "20 en_US DEC 1/1/1/0.0075", "en_US", UNUM_DECIMAL
, 1, 1, 1, 0.0075, u
"#,##0.0", 0.019, u
"0.0" },
3420 { "21 en_US DEC 1/1/2/0.0075", "en_US", UNUM_DECIMAL
, 1, 1, 2, 0.0075, u
"#,##0.0075", 0.004, u
"0.0075" }, // use incr
3421 { "22 en_US DEC 1/1/2/0.0075", "en_US", UNUM_DECIMAL
, 1, 1, 2, 0.0075, u
"#,##0.0075", 0.019, u
"0.0225" }, // use incr
3422 { "23 en_US DEC 1/1/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 1, 3, 0.0075, u
"#,##0.0075", 0.004, u
"0.0075" }, // use incr
3423 { "24 en_US DEC 1/1/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 1, 3, 0.0075, u
"#,##0.0075", 0.019, u
"0.0225" }, // use incr
3424 { "25 en_US DEC 1/2/2/0.0075", "en_US", UNUM_DECIMAL
, 1, 2, 2, 0.0075, u
"#,##0.0075", 0.004, u
"0.0075" }, // use incr
3425 { "26 en_US DEC 1/2/2/0.0075", "en_US", UNUM_DECIMAL
, 1, 2, 2, 0.0075, u
"#,##0.0075", 0.019, u
"0.0225" }, // use incr
3426 { "27 en_US DEC 1/2/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 2, 3, 0.0075, u
"#,##0.0075", 0.004, u
"0.0075" }, // use incr
3427 { "28 en_US DEC 1/2/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 2, 3, 0.0075, u
"#,##0.0075", 0.019, u
"0.0225" }, // use incr
3428 { "29 en_US DEC 1/3/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 3, 3, 0.0075, u
"#,##0.0075", 0.004, u
"0.0075" }, // use incr
3429 { "2A en_US DEC 1/3/3/0.0075", "en_US", UNUM_DECIMAL
, 1, 3, 3, 0.0075, u
"#,##0.0075", 0.019, u
"0.0225" }, // use incr
3431 // Additions for rdar://51452216
3432 { "30 en_US DEC 1/0/1/0.01", "en_US", UNUM_DECIMAL
, 1, 1, 3, 0.001, u
"#,##0.001", 1.23456789, u
"1.235" },
3433 { "31 en_US DEC 1/1/1/0.01", "en_US", UNUM_DECIMAL
, 1, 1, 3, 0.001f
, u
"#,##0.001", 1.23456789, u
"1.235" },
3435 { NULL
, NULL
, UNUM_IGNORE
, 0, 0, 0, 0.0, NULL
, 0.0, NULL
}
3438 // The following is copied from C++ number_patternstring.cpp for this C test.
3440 // Determine whether a given roundingIncrement should be ignored for formatting
3441 // based on the current maxFrac value (maximum fraction digits). For example a
3442 // roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
3443 // is 2 or more. Note that roundingIncrements are rounded in significance, so
3444 // a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
3445 // it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
3446 // 0.005 is treated like 0.001 for significance). This is the reason for the
3447 // initial doubling below.
3448 // roundIncr must be non-zero
3449 static UBool
ignoreRoundingIncrement(double roundIncr
, int32_t maxFrac
) {
3455 for (frac
= 0; frac
<= maxFrac
&& roundIncr
<= 1.0; frac
++, roundIncr
*= 10.0);
3456 return (frac
> maxFrac
);
3459 static void TestSetMaxFracAndRoundIncr(void) {
3460 const SetMaxFracAndRoundIncrItem
* itemPtr
;
3461 for (itemPtr
= maxFracAndRoundIncrItems
; itemPtr
->descrip
!= NULL
; itemPtr
++) {
3462 UChar ubuf
[kUBufMax
];
3463 char bbufe
[kBBufMax
];
3464 char bbufg
[kBBufMax
];
3466 UErrorCode status
= U_ZERO_ERROR
;
3467 UNumberFormat
* unf
= unum_open(itemPtr
->style
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3468 if (U_FAILURE(status
)) {
3469 log_data_err("locale %s: unum_open style %d fails with %s\n", itemPtr
->locale
, itemPtr
->style
, u_errorName(status
));
3473 unum_setAttribute(unf
, UNUM_MIN_INTEGER_DIGITS
, itemPtr
->minInt
);
3474 unum_setAttribute(unf
, UNUM_MIN_FRACTION_DIGITS
, itemPtr
->minFrac
);
3475 unum_setAttribute(unf
, UNUM_MAX_FRACTION_DIGITS
, itemPtr
->maxFrac
);
3476 unum_setDoubleAttribute(unf
, UNUM_ROUNDING_INCREMENT
, itemPtr
->roundIncr
);
3478 UBool roundIncrUsed
= (itemPtr
->roundIncr
!= 0.0 && !ignoreRoundingIncrement(itemPtr
->roundIncr
, itemPtr
->maxFrac
));
3480 int32_t minInt
= unum_getAttribute(unf
, UNUM_MIN_INTEGER_DIGITS
);
3481 if (minInt
!= itemPtr
->minInt
) {
3482 log_err("test %s: unum_getAttribute UNUM_MIN_INTEGER_DIGITS, expected %d, got %d\n",
3483 itemPtr
->descrip
, itemPtr
->minInt
, minInt
);
3485 int32_t minFrac
= unum_getAttribute(unf
, UNUM_MIN_FRACTION_DIGITS
);
3486 if (minFrac
!= itemPtr
->minFrac
) {
3487 log_err("test %s: unum_getAttribute UNUM_MIN_FRACTION_DIGITS, expected %d, got %d\n",
3488 itemPtr
->descrip
, itemPtr
->minFrac
, minFrac
);
3490 // If incrementRounding is used, maxFrac is set equal to minFrac
3491 int32_t maxFrac
= unum_getAttribute(unf
, UNUM_MAX_FRACTION_DIGITS
);
3492 // If incrementRounding is used, maxFrac is set equal to minFrac
3493 int32_t expMaxFrac
= (roundIncrUsed
)? itemPtr
->minFrac
: itemPtr
->maxFrac
;
3494 if (maxFrac
!= expMaxFrac
) {
3495 log_err("test %s: unum_getAttribute UNUM_MAX_FRACTION_DIGITS, expected %d, got %d\n",
3496 itemPtr
->descrip
, expMaxFrac
, maxFrac
);
3498 double roundIncr
= unum_getDoubleAttribute(unf
, UNUM_ROUNDING_INCREMENT
);
3499 // If incrementRounding is not used, roundIncr is set to 0.0
3500 double expRoundIncr
= (roundIncrUsed
)? itemPtr
->roundIncr
: 0.0;
3501 if (roundIncr
!= expRoundIncr
) {
3502 log_err("test %s: unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT, expected %f, got %f\n",
3503 itemPtr
->descrip
, expRoundIncr
, roundIncr
);
3506 status
= U_ZERO_ERROR
;
3507 ulen
= unum_toPattern(unf
, FALSE
, ubuf
, kUBufMax
, &status
);
3508 if ( U_FAILURE(status
) ) {
3509 log_err("test %s: unum_toPattern fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3510 } else if (u_strcmp(ubuf
,itemPtr
->expPattern
)!=0) {
3511 u_austrcpy(bbufe
, itemPtr
->expPattern
);
3512 u_austrcpy(bbufg
, ubuf
);
3513 log_err("test %s: unum_toPattern expect \"%s\", get \"%s\"\n", itemPtr
->descrip
, bbufe
, bbufg
);
3516 status
= U_ZERO_ERROR
;
3517 ulen
= unum_formatDouble(unf
, itemPtr
->valueToFmt
, ubuf
, kUBufMax
, NULL
, &status
);
3518 if ( U_FAILURE(status
) ) {
3519 log_err("test %s: unum_formatDouble fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3520 } else if (u_strcmp(ubuf
,itemPtr
->expFormat
)!=0) {
3521 u_austrcpy(bbufe
, itemPtr
->expFormat
);
3522 u_austrcpy(bbufg
, ubuf
);
3523 log_err("test %s: unum_formatDouble expect \"%s\", get \"%s\"\n", itemPtr
->descrip
, bbufe
, bbufg
);
3530 static void TestIgnorePadding(void) {
3531 UErrorCode status
= U_ZERO_ERROR
;
3532 UNumberFormat
* unum
= unum_open(UNUM_PATTERN_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
3533 if (U_FAILURE(status
)) {
3534 log_data_err("unum_open UNUM_PATTERN_DECIMAL for en_US and NULL pattern fails:%s\n", u_errorName(status
));
3536 unum_setAttribute(unum
, UNUM_GROUPING_USED
, 0);
3537 unum_setAttribute(unum
, UNUM_FORMAT_WIDTH
, 0);
3538 unum_setTextAttribute(unum
, UNUM_PADDING_CHARACTER
, u
"*", 1, &status
);
3539 if (U_FAILURE(status
)) {
3540 log_err("unum_setTextAttribute UNUM_PADDING_CHARACTER to '*' fails: %s\n", u_errorName(status
));
3542 unum_setAttribute(unum
, UNUM_PADDING_POSITION
, 0);
3543 unum_setAttribute(unum
, UNUM_MIN_INTEGER_DIGITS
, 0);
3544 unum_setAttribute(unum
, UNUM_MAX_INTEGER_DIGITS
, 8);
3545 unum_setAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
, 0);
3546 unum_setAttribute(unum
, UNUM_MAX_FRACTION_DIGITS
, 0);
3548 UChar ubuf
[kUBufMax
];
3549 int32_t ulen
= unum_toPattern(unum
, FALSE
, ubuf
, kUBufMax
, &status
);
3550 if (U_FAILURE(status
)) {
3551 log_err("unum_toPattern fails: %s\n", u_errorName(status
));
3553 char bbuf
[kBBufMax
];
3554 if (ulen
> 0 && ubuf
[0]==u
'*') {
3555 ubuf
[kUBufMax
-1] = 0; // ensure zero termination
3556 u_austrncpy(bbuf
, ubuf
, kBBufMax
);
3557 log_err("unum_toPattern result should ignore padding but get %s\n", bbuf
);
3559 unum_applyPattern(unum
, FALSE
, ubuf
, ulen
, NULL
, &status
);
3560 if (U_FAILURE(status
)) {
3561 log_err("unum_applyPattern fails: %s\n", u_errorName(status
));
3563 ulen
= unum_formatDecimal(unum
, "24", -1, ubuf
, kUBufMax
, NULL
, &status
);
3564 if (U_FAILURE(status
)) {
3565 log_err("unum_formatDecimal fails: %s\n", u_errorName(status
));
3566 } else if (u_strcmp(ubuf
, u
"24") != 0) {
3567 ubuf
[kUBufMax
-1] = 0; // ensure zero termination
3568 u_austrncpy(bbuf
, ubuf
, kBBufMax
);
3569 log_err("unum_formatDecimal result expect 24 but get %s\n", bbuf
);
3581 const UChar
* formatLimitPrecision
;
3582 const UChar
* formatFullPrecision
;
3583 } FormatPrecisionItem
;
3585 static const FormatPrecisionItem formatPrecisionItems
[] = {
3586 { "en_US", 0.33333333 - 0.00333333, u
"0.33", u
"0.32999999999999996" },
3587 { "en_US", 0.07 * 100.0, u
"7", u
"7.000000000000001" },
3588 { NULL
, 0.0, NULL
, NULL
}
3591 static const UChar
* patternTestPrecision
= u
"#0.################################################################################"; // 80 fraction places
3593 // Currently Apple only
3594 static void TestFormatPrecision(void) {
3595 const FormatPrecisionItem
* itemPtr
;
3596 for (itemPtr
= formatPrecisionItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
3597 UErrorCode status
= U_ZERO_ERROR
;
3599 UNumberFormat
*unum
= unum_open(UNUM_PATTERN_DECIMAL
, patternTestPrecision
, -1, itemPtr
->locale
, &perr
, &status
);
3600 if (U_FAILURE(status
)) {
3601 log_data_err("unum_open UNUM_PATTERN_DECIMAL fails for locale %s: %s\n", itemPtr
->locale
, u_errorName(status
));
3604 UChar ubuf
[kUBufSize
];
3606 UFieldPosition fpos
;
3607 UBool formatFullPrecision
;
3609 formatFullPrecision
= (UBool
)unum_getAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
);
3610 if (formatFullPrecision
) {
3611 log_err("unum_getAttribute, default for UNUM_FORMAT_WITH_FULL_PRECISION is not FALSE\n");
3613 fpos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
3614 fpos
.beginIndex
= 0;
3616 status
= U_ZERO_ERROR
;
3617 ulen
= unum_formatDouble(unum
, itemPtr
->value
, ubuf
, kUBufSize
, &fpos
, &status
);
3618 if (U_FAILURE(status
)) {
3619 log_err("unum_formatDouble locale %s val %.20f limit precision fails with %s\n", itemPtr
->locale
, itemPtr
->value
, u_errorName(status
));
3620 } else if (ulen
!= u_strlen(itemPtr
->formatLimitPrecision
) || u_strcmp(ubuf
, itemPtr
->formatLimitPrecision
) != 0) {
3621 char bbufe
[kBBufSize
];
3622 char bbufg
[kBBufSize
];
3623 u_strToUTF8(bbufe
, kBBufSize
, NULL
, itemPtr
->formatLimitPrecision
, -1, &status
);
3624 u_strToUTF8(bbufg
, kBBufSize
, NULL
, ubuf
, ulen
, &status
);
3625 log_err("unum_formatDouble locale %s val %.20f limit precision, expect %s, get %s\n", itemPtr
->locale
, itemPtr
->value
, bbufe
, bbufg
);
3629 unum_setAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
, TRUE
);
3630 formatFullPrecision
= (UBool
)unum_getAttribute(unum
, UNUM_FORMAT_WITH_FULL_PRECISION
);
3631 if (!formatFullPrecision
) {
3632 log_err("unum_getAttribute, after set UNUM_FORMAT_WITH_FULL_PRECISION is not TRUE\n");
3634 fpos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
3635 fpos
.beginIndex
= 0;
3637 status
= U_ZERO_ERROR
;
3638 ulen
= unum_formatDouble(unum
, itemPtr
->value
, ubuf
, kUBufSize
, &fpos
, &status
);
3639 if (U_FAILURE(status
)) {
3640 log_err("unum_formatDouble locale %s val %.20f full precision fails with %s\n", itemPtr
->locale
, itemPtr
->value
, u_errorName(status
));
3641 } else if (ulen
!= u_strlen(itemPtr
->formatFullPrecision
) || u_strcmp(ubuf
, itemPtr
->formatFullPrecision
) != 0) {
3642 char bbufe
[kBBufSize
];
3643 char bbufg
[kBBufSize
];
3644 u_strToUTF8(bbufe
, kBBufSize
, NULL
, itemPtr
->formatFullPrecision
, -1, &status
);
3645 u_strToUTF8(bbufg
, kBBufSize
, NULL
, ubuf
, ulen
, &status
);
3646 log_err("unum_formatDouble locale %s val %.20f full precision, expect %s, get %s\n", itemPtr
->locale
, itemPtr
->value
, bbufe
, bbufg
);
3654 // Apple only for <rdar://problem/52538227>
3655 static void TestSetSigDigAndRoundIncr(void) {
3656 UErrorCode status
= U_ZERO_ERROR
;
3657 UNumberFormat
* unum
= unum_open(UNUM_PATTERN_DECIMAL
, u
"#", 1, "en_US", NULL
, &status
);
3658 if ( U_FAILURE(status
) ) {
3659 log_data_err("unum_open UNUM_PATTERN_DECIMAL # for \"en_US\" fails with %s\n", u_errorName(status
));
3661 static const double value
= 1.034000;
3662 UChar ubuf
[kUBufMax
];
3663 char bbuf
[kBBufMax
];
3666 unum_setAttribute(unum
, UNUM_MAX_INTEGER_DIGITS
, 42);
3667 unum_setAttribute(unum
, UNUM_MAX_FRACTION_DIGITS
, 0);
3668 unum_setAttribute(unum
, UNUM_ROUNDING_MODE
, UNUM_ROUND_HALFUP
); // =6
3669 unum_setDoubleAttribute(unum
, UNUM_ROUNDING_INCREMENT
, 0.01);
3670 unum_setAttribute(unum
, UNUM_SIGNIFICANT_DIGITS_USED
, 1);
3671 unum_setAttribute(unum
, UNUM_MAX_SIGNIFICANT_DIGITS
, 5);
3672 unum_setAttribute(unum
, UNUM_MIN_SIGNIFICANT_DIGITS
, 1);
3674 log_info("unum_getAttribute minSig %d maxSig %d sigUsed %d\n",
3675 unum_getAttribute(unum
,UNUM_MIN_SIGNIFICANT_DIGITS
), unum_getAttribute(unum
,UNUM_MAX_SIGNIFICANT_DIGITS
),
3676 unum_getAttribute(unum
,UNUM_SIGNIFICANT_DIGITS_USED
));
3677 log_info("unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT %f\n", unum_getDoubleAttribute(unum
,UNUM_SIGNIFICANT_DIGITS_USED
));
3678 ulen
= unum_toPattern(unum
, FALSE
, ubuf
, kUBufMax
, &status
);
3679 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3680 if ( U_SUCCESS(status
) ) {
3681 log_info("unum_toPattern (%d): %s\n", ulen
, bbuf
);
3684 status
= U_ZERO_ERROR
;
3685 ulen
= unum_formatDouble(unum
, value
, ubuf
, kUBufMax
, NULL
, &status
);
3686 if ( U_FAILURE(status
) ) {
3687 log_err("unum_formatDouble value %.1f status %s\n", value
, u_errorName(status
));
3688 } else if (u_strcmp(ubuf
,u
"1.03") != 0) {
3689 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3690 log_err("unum_formatDouble value %.1f expected 1.03, got %s\n", value
, bbuf
);
3696 // Apple for <rdar://problem/46755430>
3698 const char* descrip
;
3700 const UChar
* setPosPrefix
;
3701 const UChar
* setPosSuffix
;
3702 const UChar
* setNegPrefix
;
3703 const UChar
* setNegSuffix
;
3704 const UChar
* expPosPrefix
;
3705 const UChar
* expPosSuffix
;
3706 const UChar
* expNegPrefix
;
3707 const UChar
* expNegSuffix
;
3708 const UChar
* expPattern
;
3710 const UChar
* expPosFormat
;
3711 const UChar
* expNegFormat
;
3712 } SetAffixOnCurrFmtItem
;
3714 static const SetAffixOnCurrFmtItem affixOnCurrFmtItems
[] = {
3715 // descrip loc sPP sPS sNP sNS ePP ePS eNP eNS ePattern value ePosFmt eNegFmt
3716 { "01 en set no affix ", "en", NULL
, NULL
, NULL
, NULL
, u
"¤", u
"", u
"-¤", u
"", u
"¤#,##0.00", 123.4, u
"¤123.40", u
"-¤123.40" },
3717 { "02 en set + prefix", "en", u
"$", NULL
, NULL
, NULL
, u
"$", u
"", u
"-¤", u
"", u
"$#,##0.00;-¤#,##0.00", 123.4, u
"$123.40", u
"-¤123.40" },
3718 { "03 en set +- prefix", "en", u
"$", NULL
, u
"-$", NULL
, u
"$", u
"", u
"-$", u
"", u
"$#,##0.00;'-'$#,##0.00", 123.4, u
"$123.40", u
"-$123.40" },
3719 { NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,0.0,NULL
,NULL
}
3722 // Apple only for <rdar://problem/46755430>
3723 static void TestSetAffixOnCurrFmt(void) {
3724 const SetAffixOnCurrFmtItem
* itemPtr
;
3725 for (itemPtr
= affixOnCurrFmtItems
; itemPtr
->descrip
!= NULL
; itemPtr
++) {
3726 UChar ubuf
[kUBufMax
];
3727 char bbufe
[kBBufMax
];
3728 char bbufg
[kBBufMax
];
3730 UErrorCode status
= U_ZERO_ERROR
;
3731 UNumberFormat
* unf
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
3732 if (U_FAILURE(status
)) {
3733 log_data_err("locale %s: unum_open UNUM_CURRENCY fails with %s\n", itemPtr
->locale
, u_errorName(status
));
3737 if (itemPtr
->setPosPrefix
) {
3738 status
= U_ZERO_ERROR
;
3739 unum_setTextAttribute(unf
, UNUM_POSITIVE_PREFIX
, itemPtr
->setPosPrefix
, -1, &status
);
3740 if (U_FAILURE(status
)) {
3741 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3744 if (itemPtr
->setPosSuffix
) {
3745 status
= U_ZERO_ERROR
;
3746 unum_setTextAttribute(unf
, UNUM_POSITIVE_SUFFIX
, itemPtr
->setPosSuffix
, -1, &status
);
3747 if (U_FAILURE(status
)) {
3748 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3751 if (itemPtr
->setNegPrefix
) {
3752 status
= U_ZERO_ERROR
;
3753 unum_setTextAttribute(unf
, UNUM_NEGATIVE_PREFIX
, itemPtr
->setNegPrefix
, -1, &status
);
3754 if (U_FAILURE(status
)) {
3755 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3758 if (itemPtr
->setNegSuffix
) {
3759 status
= U_ZERO_ERROR
;
3760 unum_setTextAttribute(unf
, UNUM_NEGATIVE_SUFFIX
, itemPtr
->setNegSuffix
, -1, &status
);
3761 if (U_FAILURE(status
)) {
3762 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3766 status
= U_ZERO_ERROR
;
3767 ulen
= unum_getTextAttribute(unf
, UNUM_POSITIVE_PREFIX
, ubuf
, kUBufMax
, &status
);
3768 if (U_FAILURE(status
)) {
3769 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3770 } else if (u_strcmp(ubuf
,itemPtr
->expPosPrefix
)!=0) {
3771 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expPosPrefix
, -1, &status
);
3772 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3773 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3775 status
= U_ZERO_ERROR
;
3776 ulen
= unum_getTextAttribute(unf
, UNUM_POSITIVE_SUFFIX
, ubuf
, kUBufMax
, &status
);
3777 if (U_FAILURE(status
)) {
3778 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3779 } else if (u_strcmp(ubuf
,itemPtr
->expPosSuffix
)!=0) {
3780 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expPosSuffix
, -1, &status
);
3781 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3782 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3784 status
= U_ZERO_ERROR
;
3785 ulen
= unum_getTextAttribute(unf
, UNUM_NEGATIVE_PREFIX
, ubuf
, kUBufMax
, &status
);
3786 if (U_FAILURE(status
)) {
3787 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3788 } else if (u_strcmp(ubuf
,itemPtr
->expNegPrefix
)!=0) {
3789 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expNegPrefix
, -1, &status
);
3790 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3791 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3793 status
= U_ZERO_ERROR
;
3794 ulen
= unum_getTextAttribute(unf
, UNUM_NEGATIVE_SUFFIX
, ubuf
, kUBufMax
, &status
);
3795 if (U_FAILURE(status
)) {
3796 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3797 } else if (u_strcmp(ubuf
,itemPtr
->expNegSuffix
)!=0) {
3798 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expNegSuffix
, -1, &status
);
3799 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3800 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3802 status
= U_ZERO_ERROR
;
3803 ulen
= unum_toPattern(unf
, FALSE
, ubuf
, kUBufMax
, &status
);
3804 if (U_FAILURE(status
)) {
3805 log_err("test %s: unum_toPattern fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3806 } else if (u_strcmp(ubuf
,itemPtr
->expPattern
)!=0) {
3807 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expPattern
, -1, &status
);
3808 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3809 log_err("test %s: unum_toPattern expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3812 status
= U_ZERO_ERROR
;
3813 ulen
= unum_formatDouble(unf
, itemPtr
->value
, ubuf
, kUBufMax
, NULL
, &status
);
3814 if (U_FAILURE(status
)) {
3815 log_err("test %s: unum_formatDouble positive fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3816 } else if (u_strcmp(ubuf
,itemPtr
->expPosFormat
)!=0) {
3817 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expPosFormat
, -1, &status
);
3818 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3819 log_err("test %s: unum_formatDouble positive expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3821 status
= U_ZERO_ERROR
;
3822 ulen
= unum_formatDouble(unf
, -1.0*itemPtr
->value
, ubuf
, kUBufMax
, NULL
, &status
);
3823 if (U_FAILURE(status
)) {
3824 log_err("test %s: unum_formatDouble negative fails with %s\n", itemPtr
->descrip
, u_errorName(status
));
3825 } else if (u_strcmp(ubuf
,itemPtr
->expNegFormat
)!=0) {
3826 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expNegFormat
, -1, &status
);
3827 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
3828 log_err("test %s: unum_formatDouble negative expect %s, get %s\n", itemPtr
->descrip
, bbufe
, bbufg
);
3835 // Apple only for <rdar://problem/46915356>
3836 static void TestParseWithEmptyCurr(void) {
3837 UErrorCode status
= U_ZERO_ERROR
;
3838 UNumberFormat
* unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
3839 if (U_FAILURE(status
)) {
3840 log_data_err("unum_open UNUM_CURRENCY for \"en_US\" fails with %s\n", u_errorName(status
));
3842 unum_setSymbol(unum
, UNUM_CURRENCY_SYMBOL
, u
"", 0, &status
);
3843 if (U_FAILURE(status
)) {
3844 log_err("unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s\n", u_errorName(status
));
3846 char bbuf
[kBBufMax
] = { 0 };
3847 UChar curr
[4] = { 0 };
3850 const UChar
* text
= u
"3";
3852 status
= U_ZERO_ERROR
;
3854 blen
= unum_parseDecimal(unum
, text
, -1, &ppos
, bbuf
, kBBufMax
, &status
);
3855 if (U_FAILURE(status
)) {
3856 log_err("unum_parseDecimal u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status
), ppos
);
3857 } else if (ppos
!= 1 || blen
!= 1 || bbuf
[0] != '3') {
3858 log_err("unum_parseDecimal expect ppos 1, blen 1, str 3; get %d, %d, %s\n", ppos
, blen
, bbuf
);
3861 status
= U_ZERO_ERROR
;
3863 val
= unum_parseDouble(unum
, text
, -1, &ppos
, &status
);
3864 if (U_FAILURE(status
)) {
3865 log_err("unum_parseDouble u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status
), ppos
);
3866 } else if (ppos
!= 1 || val
!= 3.0) {
3867 log_err("unum_parseDouble expect ppos 1, val 3.0; get %d, %.2f\n", ppos
, val
);
3870 status
= U_ZERO_ERROR
;
3872 val
= unum_parseDoubleCurrency(unum
, text
, -1, &ppos
, curr
, &status
);
3873 if (U_SUCCESS(status
)) {
3874 log_err("unum_parseDoubleCurrency u\"3\" with empty curr symbol succeeds, get ppos %d, val %.2f\n", ppos
, val
);
3880 // Additions for <rdar://problem/51938595>
3881 // "¤#,##0.00" "¤ #,##0.00" "#,##0.00 ¤" "#,##,##0.00¤"
3882 static const char* locales
[] = {"en_US", "en_NO", "en_CZ", "en_BD", NULL
};
3883 const char ** localesPtr
= locales
;
3885 while ((locale
= *localesPtr
++) != NULL
) {
3886 status
= U_ZERO_ERROR
;
3887 unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, locale
, NULL
, &status
);
3888 if (U_FAILURE(status
)) {
3889 log_data_err("locale %s unum_open UNUM_CURRENCY fails with %s\n", locale
, u_errorName(status
));
3891 char bbuf
[kBBufMax
] = { 0 };
3892 UChar curr
[4] = { 0 };
3893 UChar ubuf
[kUBufMax
];
3894 int32_t ppos
, blen
, ulen
;
3895 const double posValToUse
= 37.0;
3896 const double negValToUse
= -3.0;
3899 status
= U_ZERO_ERROR
;
3900 unum_setSymbol(unum
, UNUM_CURRENCY_SYMBOL
, u
"", 0, &status
);
3901 if (U_FAILURE(status
)) {
3902 log_err("locale %s unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s, skipping\n", locale
, u_errorName(status
));
3906 status
= U_ZERO_ERROR
;
3907 ulen
= unum_formatDouble(unum
, posValToUse
, ubuf
, kUBufMax
, NULL
, &status
);
3908 if (U_FAILURE(status
)) {
3909 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale
, posValToUse
, u_errorName(status
));
3913 status
= U_ZERO_ERROR
;
3915 val
= unum_parseDouble(unum
, ubuf
, ulen
, &ppos
, &status
);
3916 if (U_FAILURE(status
)) {
3917 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale
, u_errorName(status
), ppos
, posValToUse
);
3918 } else if (ppos
!= ulen
|| val
!= posValToUse
) {
3919 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale
, ulen
, posValToUse
, ppos
, val
);
3922 status
= U_ZERO_ERROR
;
3923 ulen
= unum_formatDouble(unum
, negValToUse
, ubuf
, kUBufMax
, NULL
, &status
);
3924 if (U_FAILURE(status
)) {
3925 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale
, negValToUse
, u_errorName(status
));
3929 status
= U_ZERO_ERROR
;
3931 val
= unum_parseDouble(unum
, ubuf
, ulen
, &ppos
, &status
);
3932 if (U_FAILURE(status
)) {
3933 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale
, u_errorName(status
), ppos
, negValToUse
);
3934 } else if (ppos
!= ulen
|| val
!= negValToUse
) {
3935 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale
, ulen
, negValToUse
, ppos
, val
);
3938 status
= U_ZERO_ERROR
;
3939 unum_applyPattern(unum
, FALSE
, u
"#,##0.00¤", -1, NULL
, &status
);
3940 if (U_FAILURE(status
)) {
3941 log_err("locale %s unum_applyPattern \"#,##0.00¤\" fails with %s, skipping\n", locale
, u_errorName(status
));
3945 status
= U_ZERO_ERROR
;
3946 ulen
= unum_formatDouble(unum
, posValToUse
, ubuf
, kUBufMax
, NULL
, &status
);
3947 if (U_FAILURE(status
)) {
3948 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale
, posValToUse
, u_errorName(status
));
3952 status
= U_ZERO_ERROR
;
3954 val
= unum_parseDouble(unum
, ubuf
, ulen
, &ppos
, &status
);
3955 if (U_FAILURE(status
)) {
3956 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale
, u_errorName(status
), ppos
, posValToUse
);
3957 } else if (ppos
!= ulen
|| val
!= posValToUse
) {
3958 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale
, ulen
, posValToUse
, ppos
, val
);
3961 status
= U_ZERO_ERROR
;
3962 ulen
= unum_formatDouble(unum
, negValToUse
, ubuf
, kUBufMax
, NULL
, &status
);
3963 if (U_FAILURE(status
)) {
3964 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale
, negValToUse
, u_errorName(status
));
3968 status
= U_ZERO_ERROR
;
3970 val
= unum_parseDouble(unum
, ubuf
, ulen
, &ppos
, &status
);
3971 if (U_FAILURE(status
)) {
3972 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale
, u_errorName(status
), ppos
, negValToUse
);
3973 } else if (ppos
!= ulen
|| val
!= negValToUse
) {
3974 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale
, ulen
, negValToUse
, ppos
, val
);
3982 // Apple only for <rdar://problem/50113359>
3983 static const UChar
* pat1
= u
"#.##E+00;-#.##E+00";
3984 static void TestSciNotationNumbers(void) {
3985 UErrorCode status
= U_ZERO_ERROR
;
3986 UNumberFormat
* unum
= unum_open(UNUM_PATTERN_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
3987 if ( U_FAILURE(status
) ) {
3988 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status
));
3990 unum_applyPattern(unum
, FALSE
, pat1
, u_strlen(pat1
), NULL
, &status
);
3991 if ( U_FAILURE(status
) ) {
3992 log_err("unum_applyPattern fails with %s\n", u_errorName(status
));
3995 UChar ubuf
[kUBufMax
];
3996 char bbuf
[kBBufMax
];
3999 unum_setAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
, 0);
4000 unum_setAttribute(unum
, UNUM_MAX_FRACTION_DIGITS
, 2147483647);
4001 log_info("unum_getAttribute minInt %d maxInt %d minFrac %d maxFrac %d\n",
4002 unum_getAttribute(unum
,UNUM_MIN_INTEGER_DIGITS
), unum_getAttribute(unum
,UNUM_MAX_INTEGER_DIGITS
),
4003 unum_getAttribute(unum
,UNUM_MIN_FRACTION_DIGITS
), unum_getAttribute(unum
,UNUM_MAX_FRACTION_DIGITS
));
4004 ulen
= unum_toPattern(unum
, FALSE
, ubuf
, kUBufMax
, &status
);
4005 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4006 if ( U_SUCCESS(status
) ) {
4007 log_info("unum_toPattern (%d): %s\n", ulen
, bbuf
);
4010 for (value
= 10.0; value
< 1000000000.0; value
*= 10.0) {
4011 status
= U_ZERO_ERROR
;
4012 ulen
= unum_formatDouble(unum
, value
, ubuf
, kUBufMax
, NULL
, &status
);
4013 if ( U_FAILURE(status
) ) {
4014 log_err("unum_formatDouble value %.1f status %s\n", value
, u_errorName(status
));
4015 } else if (u_strncmp(ubuf
,u
"1E+0",4) != 0) {
4016 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4017 log_err("unum_formatDouble value %.1f expected result to begin with 1E+0, got %s\n", value
, bbuf
);
4025 // Apple only for <rdar://problem/51601250>
4026 static const UChar
* patFmt3Exp
= u
"0.000E+00";
4027 static void TestSciNotationPrecision(void) {
4028 UErrorCode status
= U_ZERO_ERROR
;
4029 UNumberFormat
* unum
= unum_open(UNUM_PATTERN_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
4030 if ( U_FAILURE(status
) ) {
4031 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status
));
4033 unum_applyPattern(unum
, FALSE
, pat1
, u_strlen(pat1
), NULL
, &status
);
4034 if ( U_FAILURE(status
) ) {
4035 log_err("unum_applyPattern fails with %s\n", u_errorName(status
));
4038 UChar ubuf
[kUBufMax
];
4039 char bexp
[kBBufMax
];
4040 char bget
[kBBufMax
];
4043 unum_setAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
, 3);
4044 unum_setAttribute(unum
, UNUM_MAX_FRACTION_DIGITS
, 3);
4045 unum_setAttribute(unum
, UNUM_GROUPING_USED
, 0);
4047 status
= U_ZERO_ERROR
;
4048 ulen
= unum_toPattern(unum
, FALSE
, ubuf
, kUBufMax
, &status
);
4049 if ( U_FAILURE(status
) ) {
4050 log_err("unum_toPattern fails with %s\n", u_errorName(status
));
4051 } else if (u_strcmp(ubuf
,patFmt3Exp
) != 0) {
4052 u_strToUTF8(bget
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4053 log_info("unum_toPattern, get \"%s\"\n", bget
);
4056 status
= U_ZERO_ERROR
;
4057 ulen
= unum_formatDouble(unum
, 0.0, ubuf
, ulen
, NULL
, &status
);
4058 if ( U_FAILURE(status
) ) {
4059 log_err("unum_formatDouble fails with %s\n", u_errorName(status
));
4060 } else if (u_strcmp(ubuf
,patFmt3Exp
) != 0) {
4061 u_strToUTF8(bexp
, kBBufMax
, NULL
, patFmt3Exp
, -1, &status
);
4062 u_strToUTF8(bget
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4063 log_err("unum_formatDouble error, expect \"%s\", get \"%s\"\n", bexp
, bget
);
4070 // Apple only for <rdar://problem/49808819>
4071 static const char* minGroupLocale
= "pt_PT"; // has minimumGroupingDigits{"2"}
4075 const UChar
* expectDecimal
;
4076 const UChar
* expectCurrency
;
4078 static const TestMinGroupItem minGroupItems
[] = {
4079 { 123.0, "123.0", u
"123,00", u
"123,00 €" },
4080 { 1234.0, "1234.0", u
"1234,00", u
"1234,00 €" },
4081 { 12345.0, "12345.0", u
"12 345,00", u
"12 345,00 €" },
4082 { 123456.0, "123456.0", u
"123 456,00", u
"123 456,00 €" },
4083 { 1234567.0, "1234567.0", u
"1 234 567,00", u
"1 234 567,00 €" },
4084 { 12345678.0, "12345678.0", u
"12 345 678,00", u
"12 345 678,00 €" },
4085 { 0.0, NULL
, NULL
, NULL
} // terminator
4087 static void TestMinimumGrouping(void) {
4088 UErrorCode status
= U_ZERO_ERROR
;
4089 UNumberFormat
* unumd
= unum_open(UNUM_DECIMAL
, NULL
, 0, minGroupLocale
, NULL
, &status
);
4090 UNumberFormat
* unumc
= unum_open(UNUM_CURRENCY
, NULL
, 0, minGroupLocale
, NULL
, &status
);
4091 if ( U_FAILURE(status
) ) {
4092 log_data_err("unum_open UNUM_PATTERN_DECIMAL/CURRENCY for %s fails with %s\n", minGroupLocale
, u_errorName(status
));
4094 const TestMinGroupItem
* itemPtr
;
4095 unum_setAttribute(unumd
, UNUM_MIN_FRACTION_DIGITS
, 2);
4096 for (itemPtr
= minGroupItems
; itemPtr
->value
!= 0.0; itemPtr
++) {
4097 UChar ubuf
[kUBufMax
];
4098 char bbufe
[kBBufMax
];
4099 char bbufg
[kBBufMax
];
4102 status
= U_ZERO_ERROR
;
4103 ulen
= unum_formatDecimal(unumd
, itemPtr
->string
, -1, ubuf
, kUBufMax
, NULL
, &status
);
4104 if ( U_FAILURE(status
) ) {
4105 log_err("unum_formatDecimal DEC for locale %s, value %.1f fails with %s\n", minGroupLocale
, itemPtr
->value
, u_errorName(status
));
4106 } else if (u_strcmp(ubuf
, itemPtr
->expectDecimal
) != 0) {
4107 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expectDecimal
, -1, &status
);
4108 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4109 log_err("unum_formatDecimal DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4110 minGroupLocale
, itemPtr
->value
, bbufe
, bbufg
);
4113 status
= U_ZERO_ERROR
;
4114 ulen
= unum_formatDouble(unumd
, itemPtr
->value
, ubuf
, kUBufMax
, NULL
, &status
);
4115 if ( U_FAILURE(status
) ) {
4116 log_err("unum_formatDouble DEC for locale %s, value %.1f fails with %s\n", minGroupLocale
, itemPtr
->value
, u_errorName(status
));
4117 } else if (u_strcmp(ubuf
, itemPtr
->expectDecimal
) != 0) {
4118 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expectDecimal
, -1, &status
);
4119 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4120 log_err("unum_formatDouble DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4121 minGroupLocale
, itemPtr
->value
, bbufe
, bbufg
);
4124 status
= U_ZERO_ERROR
;
4125 ulen
= unum_formatDouble(unumc
, itemPtr
->value
, ubuf
, kUBufMax
, NULL
, &status
);
4126 if ( U_FAILURE(status
) ) {
4127 log_err("unum_formatDouble CUR for locale %s, value %.1f fails with %s\n", minGroupLocale
, itemPtr
->value
, u_errorName(status
));
4128 } else if (u_strcmp(ubuf
, itemPtr
->expectCurrency
) != 0) {
4129 u_strToUTF8(bbufe
, kBBufMax
, NULL
, itemPtr
->expectCurrency
, -1, &status
);
4130 u_strToUTF8(bbufg
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4131 log_err("unum_formatDouble CUR for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4132 minGroupLocale
, itemPtr
->value
, bbufe
, bbufg
);
4140 // Apple only for <rdar://problem/49120648>
4141 static const char* const numSysLocales
[] = {
4142 "en_US", "en_US@numbers=arab", "en_US@numbers=roman", "en_US@numbers=grek", "en_US@numbers=hebr",
4143 "zh@numbers=hanidec", "zh_Hant@numbers=traditional", "en@numbers=finance", NULL
4145 static void TestNumberSystemsMultiplier(void) {
4146 const char* const* localesPtr
= numSysLocales
;
4148 while ((locale
= *localesPtr
++) != NULL
) {
4149 UErrorCode status
= U_ZERO_ERROR
;
4150 UNumberFormat
*unum
= unum_open(UNUM_DECIMAL
, NULL
, 0, locale
, NULL
, &status
);
4151 if ( U_FAILURE(status
) ) {
4152 log_data_err("unum_open UNUM_DECIMAL for %s fails with %s\n", locale
, u_errorName(status
));
4154 int32_t multiplier
= unum_getAttribute(unum
, UNUM_MULTIPLIER
);
4155 log_info("for locale %s with UNUM_DECIMAL, UNUM_MULTIPLIER is %d\n", locale
, multiplier
);
4161 // Apple only for <rdar://problem/39156484>
4164 const UChar
* stringToParse
;
4167 } ParseScientificItem
;
4168 static const ParseScientificItem parseSciItems
[] = {
4169 { "en_US", u
"4E\u200E+05", 400000.0, 6 },
4170 { "en_US", u
"4E+05", 400000.0, 5 },
4171 { "en_US", u
"4E\u200E-02", 0.04, 6 },
4172 { "en_US", u
"4E-02", 0.04, 5 },
4173 { "he_IL", u
"4E\u200E+05", 400000.0, 6 },
4174 { "he_IL", u
"4E+05", 400000.0, 5 },
4175 { "he_IL", u
"4E\u200E-02", 0.04, 6 },
4176 { "he_IL", u
"4E-02", 0.04, 5 },
4177 { "en@numbers=arabext", u
"\u06F4\u00D7\u06F1\u06F0^\u200E+\u200E\u06F0\u06F5", 400000.0, 10 },
4178 { "en@numbers=arabext", u
"\u06F4\u00D7\u06F1\u06F0^+\u06F0\u06F5", 400000.0, 8 },
4179 { NULL
,NULL
, 0.0, 0 } // terminator
4181 static void TestParseScientific(void) {
4182 const ParseScientificItem
* itemPtr
;
4183 for (itemPtr
= parseSciItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
4184 UErrorCode status
= U_ZERO_ERROR
;
4185 UNumberFormat
*unum
= unum_open(UNUM_SCIENTIFIC
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
4186 if ( U_FAILURE(status
) ) {
4187 log_data_err("unum_open UNUM_SCIENTIFIC for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4189 int32_t parsePos
= 0;
4190 double result
= unum_parseDouble(unum
, itemPtr
->stringToParse
, -1, &parsePos
, &status
);
4191 if ( U_FAILURE(status
) ) {
4192 log_err("unum_parseDouble for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4193 } else if (result
!= itemPtr
->expectValue
|| parsePos
!= itemPtr
->expectPos
) {
4194 log_err("unum_parseDouble for %s, expected result %.1f pos %d, got %.1f %d\n",
4195 itemPtr
->locale
, itemPtr
->expectValue
, itemPtr
->expectPos
, result
, parsePos
);
4202 // Apple only for <rdar://problem/51985640>
4205 const UChar
* expCurrCode
;
4206 } LocaleCurrCodeItem
;
4207 static const LocaleCurrCodeItem currCodeItems
[] = {
4208 { "en", u
"" }, // curr ICU has "XXX"
4209 { "en@currency=EUR", u
"EUR" },
4210 { "en_US", u
"USD" },
4211 { "en_ZZ", u
"XAG" },
4214 { "us", u
"" }, // curr ICU has "XXX"
4215 { "", u
"" }, // curr ICU has "XXX"
4218 static void TestCurrForUnkRegion(void) {
4219 const LocaleCurrCodeItem
* itemPtr
;
4220 for (itemPtr
= currCodeItems
; itemPtr
->locale
!= NULL
; itemPtr
++) {
4221 UErrorCode status
= U_ZERO_ERROR
;
4222 UNumberFormat
* unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
4223 if ( U_FAILURE(status
) ) {
4224 log_data_err("unum_open UNUM_CURRENCY for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4226 UChar ubuf
[kUBufMax
];
4227 int32_t ulen
= unum_getTextAttribute(unum
, UNUM_CURRENCY_CODE
, ubuf
, kUBufMax
, &status
);
4228 if ( U_FAILURE(status
) ) {
4229 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4230 } else if (u_strcmp(ubuf
,itemPtr
->expCurrCode
)!=0) {
4231 char bexp
[kBBufMax
];
4232 char bget
[kBBufMax
];
4233 u_strToUTF8(bexp
, kBBufMax
, NULL
, itemPtr
->expCurrCode
, -1, &status
);
4234 u_strToUTF8(bget
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4235 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect \"%s\" but get \"%s\"\n", itemPtr
->locale
, bexp
, bget
);
4237 status
= U_ZERO_ERROR
;
4238 unum_setTextAttribute(unum
, UNUM_CURRENCY_CODE
, u
"XXX", 3, &status
);
4239 if ( U_FAILURE(status
) ) {
4240 log_err("unum_setTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4242 ulen
= unum_getTextAttribute(unum
, UNUM_CURRENCY_CODE
, ubuf
, kUBufMax
, &status
);
4243 if ( U_FAILURE(status
) ) {
4244 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE XXX for %s fails with %s\n", itemPtr
->locale
, u_errorName(status
));
4245 } else if (u_strcmp(ubuf
,u
"XXX")!=0) {
4246 char bget
[kBBufMax
];
4247 u_strToUTF8(bget
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4248 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect XXX but get \"%s\"\n", itemPtr
->locale
, bget
);
4256 static void TestMinIntMinFracZero(void) {
4257 UErrorCode status
= U_ZERO_ERROR
;
4258 UNumberFormat
* unum
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
4259 if ( U_FAILURE(status
) ) {
4260 log_data_err("unum_open UNUM_DECIMAL for en_US fails with %s\n", u_errorName(status
));
4262 UChar ubuf
[kUBufMax
];
4263 char bbuf
[kBBufMax
];
4264 int minInt
, minFrac
, ulen
;
4266 unum_setAttribute(unum
, UNUM_MIN_INTEGER_DIGITS
, 0);
4267 unum_setAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
, 0);
4268 minInt
= unum_getAttribute(unum
, UNUM_MIN_INTEGER_DIGITS
);
4269 minFrac
= unum_getAttribute(unum
, UNUM_MIN_FRACTION_DIGITS
);
4270 if (minInt
!= 0 || minFrac
!= 0) {
4271 log_err("after setting minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt
, minFrac
);
4273 ulen
= unum_toPattern(unum
, FALSE
, ubuf
, kUBufMax
, &status
);
4274 if ( U_SUCCESS(status
) ) {
4275 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4276 log_info("after setting minInt=minFrac=0, pattern (%d): %s\n", ulen
, bbuf
);
4279 status
= U_ZERO_ERROR
;
4280 ulen
= unum_formatDouble(unum
, 10.0, ubuf
, kUBufMax
, NULL
, &status
);
4281 if ( U_FAILURE(status
) ) {
4282 log_err("unum_formatDouble 10.0 ulen %d fails with %s\n", ulen
, u_errorName(status
));
4283 } else if (u_strcmp(ubuf
, u
"10") != 0) {
4284 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4285 log_err("unum_formatDouble 10.0 expected \"10\", got \"%s\"\n", bbuf
);
4288 status
= U_ZERO_ERROR
;
4289 ulen
= unum_formatDouble(unum
, 0.9, ubuf
, kUBufMax
, NULL
, &status
);
4290 if ( U_FAILURE(status
) ) {
4291 log_err("unum_formatDouble 0.9 ulen %d fails with %s\n", ulen
, u_errorName(status
));
4292 } else if (u_strcmp(ubuf
, u
".9") != 0) {
4293 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4294 log_err("unum_formatDouble 0.9 expected \".9\", got \"%s\"\n", bbuf
);
4297 status
= U_ZERO_ERROR
;
4298 ulen
= unum_formatDouble(unum
, 0.0, ubuf
, kUBufMax
, NULL
, &status
);
4299 if ( U_FAILURE(status
) ) {
4300 log_err("unum_formatDouble 0.0 ulen %d fails with %s\n", ulen
, u_errorName(status
));
4301 } else if (u_strcmp(ubuf
, u
"0") != 0) {
4302 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4303 log_err("unum_formatDouble 0.0 expected \"0\", got \"%s\"\n", bbuf
);
4312 #if U_PLATFORM_IS_DARWIN_BASED
4314 #include <mach/mach_time.h>
4315 #define GET_START() mach_absolute_time()
4316 #define GET_DURATION(start, info) ((mach_absolute_time() - start) * info.numer)/info.denom
4317 #elif !U_PLATFORM_HAS_WIN32_API
4319 #include "putilimp.h"
4320 #define GET_START() (uint64_t)uprv_getUTCtime()
4321 #define GET_DURATION(start, info) ((uint64_t)uprv_getUTCtime() - start)
4323 #include "putilimp.h"
4324 #define GET_START() (unsigned long long)uprv_getUTCtime()
4325 #define GET_DURATION(start, info) ((unsigned long long)uprv_getUTCtime() - start)
4328 // Apple only for <rdar://problem/51672521>
4330 static void TestFormatDecPerf(void) {
4331 static const char* locales
[] =
4332 { "en_US", "ar_EG", "ar_EG@numbers=latn", "zh_CN@numbers=traditional", NULL
};
4333 static const UNumberFormatStyle styles
[] =
4334 { UNUM_DECIMAL
, UNUM_CURRENCY
, UNUM_PATTERN_DECIMAL
, UNUM_FORMAT_STYLE_COUNT
};
4335 static const char* values
[] =
4336 { "123.4", "234.5", "345.6", "456.7", NULL
};
4337 static const UChar
* pattern
= u
"#";
4338 #if U_PLATFORM_IS_DARWIN_BASED
4339 mach_timebase_info_data_t info
;
4340 mach_timebase_info(&info
);
4342 const char** localesPtr
= locales
;
4344 while ((locale
= *localesPtr
++) != NULL
) {
4345 const UNumberFormatStyle
* stylesPtr
= styles
;
4346 UNumberFormatStyle style
;
4347 while ((style
= *stylesPtr
++) < UNUM_FORMAT_STYLE_COUNT
) {
4348 #if !U_PLATFORM_HAS_WIN32_API
4349 uint64_t start
, duration
;
4351 unsigned long long start
, duration
;
4353 UErrorCode status
= U_ZERO_ERROR
;
4354 const UChar
* patternPtr
= (style
== UNUM_PATTERN_DECIMAL
)? pattern
: NULL
;
4355 int32_t patternLen
= (style
== UNUM_PATTERN_DECIMAL
)? u_strlen(pattern
): 0;
4356 UNumberFormat
*unum
;
4358 start
= GET_START();
4359 unum
= unum_open(style
, patternPtr
, patternLen
, locale
, NULL
, &status
);
4360 duration
= GET_DURATION(start
, info
);
4361 log_info("== start locale %s, style %d\n", locale
, (int)style
);
4362 if ( U_FAILURE(status
) ) {
4363 log_data_err("unum_open fails with %s\n", u_errorName(status
));
4365 log_info("unum_open nsec %5llu\n", duration
);
4366 const char** valuesPtr
= values
;
4368 while ((value
= *valuesPtr
++) != NULL
) {
4369 UChar ubuf
[kUBufMax
];
4370 char bbuf
[kBBufMax
];
4373 status
= U_ZERO_ERROR
;
4374 start
= GET_START();
4375 ulen
= unum_formatDecimal(unum
, value
, strlen(value
), ubuf
, kUBufMax
, NULL
, &status
);
4376 duration
= GET_DURATION(start
, info
);
4377 u_strToUTF8(bbuf
, kBBufMax
, NULL
, ubuf
, ulen
, &status
);
4378 if ( U_FAILURE(status
) ) {
4379 log_err("unum_formatDecimal %s fails with %s\n", value
, u_errorName(status
));
4381 log_info("unum_formatDecimal %s, nsec %5llu, result %s\n", value
, duration
, bbuf
);
4394 #endif /* APPLE_ADDITIONS */
4396 #endif /* #if !UCONFIG_NO_FORMATTING */