1 /********************************************************************
3 * Copyright (c) 1997-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6 /********************************************************************************
10 * Madhu Katragadda Creation
12 * Modification History:
14 * Date Name Description
15 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
16 * 07/15/99 helena Ported to HPUX 10/11 CC.
17 *********************************************************************************
20 /* C API TEST FOR NUMBER FORMAT */
22 #include "unicode/utypes.h"
24 #if !UCONFIG_NO_FORMATTING
26 #include "unicode/uloc.h"
27 #include "unicode/umisc.h"
28 #include "unicode/unum.h"
29 #include "unicode/ustring.h"
37 #define LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
39 static const char *tagAssert(const char *f
, int32_t l
, const char *msg
) {
40 static char _fileline
[1000];
41 sprintf(_fileline
, "%s:%d: ASSERT_TRUE(%s)", f
, l
, msg
);
45 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
47 void addNumForTest(TestNode
** root
);
48 static void TestTextAttributeCrash(void);
49 static void TestNBSPInPattern(void);
50 static void TestInt64Parse(void);
51 static void TestParseCurrency(void);
52 static void TestParseAltNum(void);
53 static void TestMaxInt(void);
54 static void TestNoExponent(void);
56 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
58 void addNumForTest(TestNode
** root
)
60 TESTCASE(TestNumberFormat
);
61 TESTCASE(TestSpelloutNumberParse
);
62 TESTCASE(TestSignificantDigits
);
63 TESTCASE(TestSigDigRounding
);
64 TESTCASE(TestNumberFormatPadding
);
65 TESTCASE(TestInt64Format
);
66 TESTCASE(TestNonExistentCurrency
);
67 TESTCASE(TestCurrencyRegression
);
68 TESTCASE(TestTextAttributeCrash
);
69 TESTCASE(TestRBNFFormat
);
70 TESTCASE(TestNBSPInPattern
);
71 TESTCASE(TestInt64Parse
);
72 TESTCASE(TestParseZero
);
73 TESTCASE(TestParseCurrency
);
74 TESTCASE(TestCloneWithRBNF
);
76 TESTCASE(TestNoExponent
);
77 TESTCASE(TestParseAltNum
);
80 /* test Parse int 64 */
82 static void TestInt64Parse()
85 UErrorCode st
= U_ZERO_ERROR
;
86 UErrorCode
* status
= &st
;
88 const char* st1
= "009223372036854775808";
97 u_charsToUChars(st1
, text
, size
);
98 nf
= unum_open(UNUM_DEFAULT
, NULL
, -1, NULL
, NULL
, status
);
100 if(U_FAILURE(*status
))
102 log_data_err("Error in unum_open() %s \n", myErrorName(*status
));
106 log_verbose("About to test unum_parseInt64() with out of range number\n");
108 a
= unum_parseInt64(nf
, text
, size
, 0, status
);
111 if(!U_FAILURE(*status
))
113 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status
));
117 log_verbose("unum_parseInt64() successful\n");
124 /* test Number Format API */
125 static void TestNumberFormat()
136 int32_t resultlength
;
137 int32_t resultlengthneeded
;
141 double d
= -10456.37;
142 double a
= 1234.56, a1
= 1235.0;
143 int32_t l
= 100000000;
149 UNumberFormatAttribute attr
;
150 UNumberFormatSymbol symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
;
152 UErrorCode status
=U_ZERO_ERROR
;
153 UNumberFormatStyle style
= UNUM_DEFAULT
;
154 UNumberFormat
*pattern
;
155 UNumberFormat
*def
, *fr
, *cur_def
, *cur_fr
, *per_def
, *per_fr
,
156 *cur_frpattern
, *myclone
, *spellout_def
;
158 /* Testing unum_open() with various Numberformat styles and locales*/
159 status
= U_ZERO_ERROR
;
160 log_verbose("Testing unum_open() with default style and locale\n");
161 def
=unum_open(style
, NULL
,0,NULL
, NULL
,&status
);
163 /* Might as well pack it in now if we can't even get a default NumberFormat... */
164 if(U_FAILURE(status
))
166 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status
));
170 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
171 fr
=unum_open(style
,NULL
,0, "fr_FR",NULL
, &status
);
172 if(U_FAILURE(status
))
173 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status
));
175 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
177 /* Can't hardcode the result to assume the default locale is "en_US". */
178 cur_def
=unum_open(style
, NULL
,0,"en_US", NULL
, &status
);
179 if(U_FAILURE(status
))
180 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
181 myErrorName(status
) );
183 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
184 cur_fr
=unum_open(style
,NULL
,0, "fr_FR", NULL
, &status
);
185 if(U_FAILURE(status
))
186 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
187 myErrorName(status
));
189 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
191 per_def
=unum_open(style
,NULL
,0, NULL
,NULL
, &status
);
192 if(U_FAILURE(status
))
193 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status
));
195 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
196 per_fr
=unum_open(style
, NULL
,0,"fr_FR", NULL
,&status
);
197 if(U_FAILURE(status
))
198 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status
));
200 log_verbose("\nTesting unum_open(spellout, NULL, status)");
202 spellout_def
=unum_open(style
, NULL
, 0, "en_US", NULL
, &status
);
203 if(U_FAILURE(status
))
204 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status
));
206 /* Testing unum_clone(..) */
207 log_verbose("\nTesting unum_clone(fmt, status)");
208 status
= U_ZERO_ERROR
;
209 myclone
= unum_clone(def
,&status
);
210 if(U_FAILURE(status
))
211 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status
));
214 log_verbose("unum_clone() successful\n");
217 /*Testing unum_getAvailable() and unum_countAvailable()*/
218 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
219 numlocales
=unum_countAvailable();
221 log_err("error in countAvailable");
223 log_verbose("unum_countAvialable() successful\n");
224 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales
);
226 for(i
=0;i
<numlocales
;i
++)
228 log_verbose("%s\n", unum_getAvailable(i
));
229 if (unum_getAvailable(i
) == 0)
230 log_err("No locale for which number formatting patterns are applicable\n");
232 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i
));
236 /*Testing unum_format() and unum_formatdouble()*/
237 u_uastrcpy(temp1
, "$100,000,000.00");
239 log_verbose("\nTesting unum_format() \n");
241 pos1
.field
= UNUM_INTEGER_FIELD
;
242 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
243 if(status
==U_BUFFER_OVERFLOW_ERROR
)
246 resultlength
=resultlengthneeded
+1;
247 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
248 /* for (i = 0; i < 100000; i++) */
250 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
254 if(U_FAILURE(status
))
256 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
) );
258 if(u_strcmp(result
, temp1
)==0)
259 log_verbose("Pass: Number formatting using unum_format() successful\n");
261 log_err("Fail: Error in number Formatting using unum_format()\n");
262 if(pos1
.beginIndex
== 1 && pos1
.endIndex
== 12)
263 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
265 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
266 pos1
.beginIndex
, pos1
.endIndex
);
271 log_verbose("\nTesting unum_formatDouble()\n");
272 u_uastrcpy(temp1
, "($10,456.37)");
274 pos2
.field
= UNUM_FRACTION_FIELD
;
275 resultlengthneeded
=unum_formatDouble(cur_def
, d
, NULL
, resultlength
, &pos2
, &status
);
276 if(status
==U_BUFFER_OVERFLOW_ERROR
)
279 resultlength
=resultlengthneeded
+1;
280 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
281 /* for (i = 0; i < 100000; i++) */
283 unum_formatDouble(cur_def
, d
, result
, resultlength
, &pos2
, &status
);
286 if(U_FAILURE(status
))
288 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
290 if(result
&& u_strcmp(result
, temp1
)==0)
291 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
293 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
294 if(pos2
.beginIndex
== 9 && pos2
.endIndex
== 11)
295 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
297 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
298 pos1
.beginIndex
, pos1
.endIndex
);
301 /* Testing unum_parse() and unum_parseDouble() */
302 log_verbose("\nTesting unum_parseDouble()\n");
303 /* for (i = 0; i < 100000; i++)*/
305 if (result
!= NULL
) {
306 d1
=unum_parseDouble(cur_def
, result
, u_strlen(result
), &parsepos
, &status
);
308 log_err("result is NULL\n");
310 if(U_FAILURE(status
)) {
311 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result
,u_strlen(result
)),parsepos
, myErrorName(status
));
315 log_err("Fail: Error in parsing\n");
317 log_verbose("Pass: parsing successful\n");
322 status
= U_ZERO_ERROR
;
323 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
324 log_verbose("\nTesting unum_formatDoubleCurrency\n");
325 u_uastrcpy(temp1
, "Y1,235");
326 temp1
[0] = 0xA5; /* Yen sign */
327 u_uastrcpy(temp
, "JPY");
329 pos2
.field
= UNUM_INTEGER_FIELD
;
330 resultlengthneeded
=unum_formatDoubleCurrency(cur_def
, a
, temp
, NULL
, resultlength
, &pos2
, &status
);
331 if (status
==U_BUFFER_OVERFLOW_ERROR
) {
333 resultlength
=resultlengthneeded
+1;
334 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
335 unum_formatDoubleCurrency(cur_def
, a
, temp
, result
, resultlength
, &pos2
, &status
);
337 if (U_FAILURE(status
)) {
338 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
340 if (result
&& u_strcmp(result
, temp1
)==0) {
341 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
343 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
345 if (pos2
.beginIndex
== 1 && pos2
.endIndex
== 6) {
346 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
348 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
349 pos1
.beginIndex
, pos1
.endIndex
);
352 log_verbose("\nTesting unum_parseDoubleCurrency\n");
354 if (result
== NULL
) {
355 log_err("result is NULL\n");
358 d1
=unum_parseDoubleCurrency(cur_def
, result
, u_strlen(result
), &parsepos
, temp2
, &status
);
359 if (U_FAILURE(status
)) {
360 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result
, u_strlen(result
)), myErrorName(status
));
362 /* Note: a==1234.56, but on parse expect a1=1235.0 */
364 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1
, a1
);
366 log_verbose("Pass: parsed currency ammount successfully\n");
368 if (u_strcmp(temp2
, temp
)==0) {
369 log_verbose("Pass: parsed correct currency\n");
371 log_err("Fail: parsed incorrect currency\n");
374 status
= U_ZERO_ERROR
; /* reset */
380 /* performance testing */
381 u_uastrcpy(temp1
, "$462.12345");
382 resultlength
=u_strlen(temp1
);
383 /* for (i = 0; i < 100000; i++) */
386 d1
=unum_parseDouble(cur_def
, temp1
, resultlength
, &parsepos
, &status
);
388 if(U_FAILURE(status
))
390 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1
, resultlength
), myErrorName(status
));
394 * Note: "for strict standard conformance all operations and constants are now supposed to be
395 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
400 log_err("Fail: Error in parsing\n");
402 log_verbose("Pass: parsing successful\n");
406 u_uastrcpy(temp1
, "($10,456.3E1])");
408 d1
=unum_parseDouble(cur_def
, temp1
, u_strlen(temp1
), &parsepos
, &status
);
409 if(U_SUCCESS(status
))
411 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1
, myErrorName(status
));
415 log_verbose("\nTesting unum_format()\n");
419 resultlengthneeded
=unum_format(per_fr
, l
, NULL
, resultlength
, &pos1
, &status
);
420 if(status
==U_BUFFER_OVERFLOW_ERROR
)
423 resultlength
=resultlengthneeded
+1;
424 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
425 /* for (i = 0; i < 100000; i++)*/
427 unum_format(per_fr
, l
, result
, resultlength
, &pos1
, &status
);
430 if(U_FAILURE(status
))
432 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
436 log_verbose("\nTesting unum_parse()\n");
437 /* for (i = 0; i < 100000; i++) */
440 l1
=unum_parse(per_fr
, result
, u_strlen(result
), &parsepos
, &status
);
442 if(U_FAILURE(status
))
444 log_err("parse failed. The error is : %s\n", myErrorName(status
));
448 log_err("Fail: Error in parsing\n");
450 log_verbose("Pass: parsing successful\n");
454 /* create a number format using unum_openPattern(....)*/
455 log_verbose("\nTesting unum_openPattern()\n");
456 u_uastrcpy(temp1
, "#,##0.0#;(#,##0.0#)");
457 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
458 if(U_FAILURE(status
))
460 log_err("error in unum_openPattern(): %s\n", myErrorName(status
) );;
463 log_verbose("Pass: unum_openPattern() works fine\n");
465 /*test for unum_toPattern()*/
466 log_verbose("\nTesting unum_toPattern()\n");
468 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
469 if(status
==U_BUFFER_OVERFLOW_ERROR
)
472 resultlength
=resultlengthneeded
+1;
473 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
474 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
476 if(U_FAILURE(status
))
478 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
482 if(u_strcmp(result
, temp1
)!=0)
483 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
485 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
489 /*Testing unum_getSymbols() and unum_setSymbols()*/
490 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
491 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
493 resultlengthneeded
=unum_toPattern(cur_def
, FALSE
, NULL
, resultlength
, &status
);
494 if(status
==U_BUFFER_OVERFLOW_ERROR
)
497 resultlength
=resultlengthneeded
+1;
498 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
499 unum_toPattern(cur_def
, FALSE
, result
, resultlength
, &status
);
501 if(U_FAILURE(status
))
503 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status
));
507 cur_frpattern
=unum_open(UNUM_IGNORE
,result
, u_strlen(result
), "fr_FR",NULL
, &status
);
508 if(U_FAILURE(status
))
510 log_err("error in unum_openPattern(): %s\n", myErrorName(status
));
515 /*getting the symbols of cur_def */
516 /*set the symbols of cur_frpattern to cur_def */
517 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
519 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
520 unum_setSymbol(cur_frpattern
, symType
, temp1
, -1, &status
);
521 if(U_FAILURE(status
))
523 log_err("Error in get/set symbols: %s\n", myErrorName(status
));
527 /*format to check the result */
529 resultlengthneeded
=unum_format(cur_def
, l
, NULL
, resultlength
, &pos1
, &status
);
530 if(status
==U_BUFFER_OVERFLOW_ERROR
)
533 resultlength
=resultlengthneeded
+1;
534 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
535 unum_format(cur_def
, l
, result
, resultlength
, &pos1
, &status
);
537 if(U_FAILURE(status
))
539 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
542 if(U_FAILURE(status
)){
543 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status
));
545 unum_applyPattern(cur_frpattern
, FALSE
, result
, u_strlen(result
),NULL
,NULL
);
547 for (symType
= UNUM_DECIMAL_SEPARATOR_SYMBOL
; symType
< UNUM_FORMAT_SYMBOL_COUNT
; symType
++) {
549 unum_getSymbol(cur_def
, symType
, temp1
, sizeof(temp1
), &status
);
550 unum_getSymbol(cur_frpattern
, symType
, temp2
, sizeof(temp2
), &status
);
551 if(U_FAILURE(status
) || u_strcmp(temp1
, temp2
) != 0)
553 log_err("Fail: error in getting symbols\n");
556 log_verbose("Pass: get and set symbols successful\n");
559 /*format and check with the previous result */
562 resultlengthneeded
=unum_format(cur_frpattern
, l
, NULL
, resultlength
, &pos1
, &status
);
563 if(status
==U_BUFFER_OVERFLOW_ERROR
)
566 resultlength
=resultlengthneeded
+1;
567 unum_format(cur_frpattern
, l
, temp1
, resultlength
, &pos1
, &status
);
569 if(U_FAILURE(status
))
571 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status
));
574 * This test fails because we have not called unum_applyPattern().
575 * Currently, such an applyPattern() does not exist on the C API, and
576 * we have jitterbug 411 for it.
577 * Since it is close to the 1.5 release, I (markus) am disabling this test just
578 * for this release (I added the test itself only last week).
579 * For the next release, we need to fix this.
580 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
582 if(u_strcmp(result
, temp1
) != 0) {
583 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result
, temp1
);
591 /* Testing unum_get/setSymbol() */
592 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
593 symbol
[0] = (UChar
)(0x41 + i
);
594 symbol
[1] = (UChar
)(0x61 + i
);
595 unum_setSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, 2, &status
);
596 if(U_FAILURE(status
)) {
597 log_err("Error from unum_setSymbol(%d): %s\n", i
, myErrorName(status
));
601 for(i
= 0; i
< UNUM_FORMAT_SYMBOL_COUNT
; ++i
) {
602 resultlength
= unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
603 if(U_FAILURE(status
)) {
604 log_err("Error from unum_getSymbol(%d): %s\n", i
, myErrorName(status
));
607 if(resultlength
!= 2 || symbol
[0] != 0x41 + i
|| symbol
[1] != 0x61 + i
) {
608 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i
);
611 /*try getting from a bogus symbol*/
612 unum_getSymbol(cur_frpattern
, (UNumberFormatSymbol
)i
, symbol
, sizeof(symbol
)/U_SIZEOF_UCHAR
, &status
);
613 if(U_SUCCESS(status
)){
614 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
616 if(U_FAILURE(status
)){
617 if(status
!= U_ILLEGAL_ARGUMENT_ERROR
){
618 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status
));
623 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
624 log_verbose("\nTesting getting and setting text attributes\n");
626 unum_getTextAttribute(cur_fr
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
627 if(U_FAILURE(status
))
629 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
631 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
632 if(U_FAILURE(status
))
634 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
636 unum_getTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, suffix
, resultlength
, &status
);
637 if(U_FAILURE(status
))
639 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status
));
641 if(u_strcmp(suffix
,temp
)!=0)
642 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
644 log_verbose("Pass: setting and getting suffix works fine\n");
645 /*set it back to normal */
646 u_uastrcpy(temp
,"$");
647 unum_setTextAttribute(cur_def
, UNUM_NEGATIVE_SUFFIX
, temp
, u_strlen(temp
), &status
);
649 /*checking some more text setter conditions */
650 u_uastrcpy(prefix
, "+");
651 unum_setTextAttribute(def
, UNUM_POSITIVE_PREFIX
, prefix
, u_strlen(prefix
) , &status
);
652 if(U_FAILURE(status
))
654 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
656 unum_getTextAttribute(def
, UNUM_POSITIVE_PREFIX
, temp
, resultlength
, &status
);
657 if(U_FAILURE(status
))
659 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
662 if(u_strcmp(prefix
, temp
)!=0)
663 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
665 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
667 u_uastrcpy(prefix
, "+");
668 unum_setTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, prefix
, u_strlen(prefix
), &status
);
669 if(U_FAILURE(status
))
671 log_err("error in setting the text attributes : %s\n", myErrorName(status
));
673 unum_getTextAttribute(def
, UNUM_NEGATIVE_PREFIX
, temp
, resultlength
, &status
);
674 if(U_FAILURE(status
))
676 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
678 if(u_strcmp(prefix
, temp
)!=0)
679 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
681 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
683 u_uastrcpy(suffix
, "+");
684 unum_setTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
685 if(U_FAILURE(status
))
687 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
690 unum_getTextAttribute(def
, UNUM_NEGATIVE_SUFFIX
, temp
, resultlength
, &status
);
691 if(U_FAILURE(status
))
693 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
695 if(u_strcmp(suffix
, temp
)!=0)
696 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
698 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
700 u_uastrcpy(suffix
, "++");
701 unum_setTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, suffix
, u_strlen(suffix
) , &status
);
702 if(U_FAILURE(status
))
704 log_err("error in setting the text attributes: %s\n", myErrorName(status
));
707 unum_getTextAttribute(def
, UNUM_POSITIVE_SUFFIX
, temp
, resultlength
, &status
);
708 if(U_FAILURE(status
))
710 log_err("error in getting the text attributes : %s\n", myErrorName(status
));
712 if(u_strcmp(suffix
, temp
)!=0)
713 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
715 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
717 /*Testing unum_getAttribute and unum_setAttribute() */
718 log_verbose("\nTesting get and set Attributes\n");
719 attr
=UNUM_GROUPING_SIZE
;
720 newvalue
=unum_getAttribute(def
, attr
);
722 unum_setAttribute(def
, attr
, newvalue
);
723 if(unum_getAttribute(def
,attr
)!=2)
724 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
726 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
728 attr
=UNUM_MULTIPLIER
;
729 newvalue
=unum_getAttribute(def
, attr
);
731 unum_setAttribute(def
, attr
, newvalue
);
732 if(unum_getAttribute(def
,attr
) != 8)
733 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
735 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
737 attr
=UNUM_SECONDARY_GROUPING_SIZE
;
738 newvalue
=unum_getAttribute(def
, attr
);
740 unum_setAttribute(def
, attr
, newvalue
);
741 if(unum_getAttribute(def
,attr
) != 2)
742 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
744 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
746 /*testing set and get Attributes extensively */
747 log_verbose("\nTesting get and set attributes extensively\n");
748 for(attr
=UNUM_PARSE_INT_ONLY
; attr
<= UNUM_PADDING_POSITION
; attr
=(UNumberFormatAttribute
)((int32_t)attr
+ 1) )
750 newvalue
=unum_getAttribute(fr
, attr
);
751 unum_setAttribute(def
, attr
, newvalue
);
752 if(unum_getAttribute(def
,attr
)!=unum_getAttribute(fr
, attr
))
753 log_err("error in setting and getting attributes\n");
755 log_verbose("Pass: attributes set and retrieved successfully\n");
758 /*testing spellout format to make sure we can use it successfully.*/
759 log_verbose("\nTesting spellout format\n");
762 static const int32_t values
[] = { 0, -5, 105, 1005, 105050 };
763 for (i
= 0; i
< LENGTH(values
); ++i
) {
766 int32_t value
= values
[i
];
767 status
= U_ZERO_ERROR
;
768 len
= unum_format(spellout_def
, value
, buffer
, LENGTH(buffer
), NULL
, &status
);
769 if(U_FAILURE(status
)) {
770 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
774 /*ustrToAstr(buffer, len, logbuf, LENGTH(logbuf));*/
775 log_verbose("formatted %d as '%s', length: %d\n", value
, aescstrdup(buffer
, len
), len
);
777 parseResult
= unum_parse(spellout_def
, buffer
, len
, &pp
, &status
);
778 if (U_FAILURE(status
)) {
779 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status
));
780 } else if (parseResult
!= value
) {
781 log_err("unum_format result %d != value %d\n", parseResult
, value
);
787 log_err("Spellout format is unavailable\n");
790 { /* Test for ticket #7079 */
791 UNumberFormat
* dec_en
;
792 UChar groupingSep
[] = { 0 };
793 UChar numPercent
[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
794 double parseResult
= 0.0;
797 dec_en
= unum_open(UNUM_DECIMAL
, NULL
, 0, "en_US", NULL
, &status
);
798 unum_setAttribute(dec_en
, UNUM_LENIENT_PARSE
, 0);
799 unum_setSymbol(dec_en
, UNUM_GROUPING_SEPARATOR_SYMBOL
, groupingSep
, 0, &status
);
800 parseResult
= unum_parseDouble(dec_en
, numPercent
, -1, NULL
, &status
);
801 /* Without the fix in #7079, the above call will hang */
802 if ( U_FAILURE(status
) || parseResult
!= 12.0 ) {
803 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
804 myErrorName(status
), parseResult
);
806 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
811 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
812 to verify that it is taking the pure decimal path. */
814 const char *bdpattern
= "#,##0.#########";
815 const char *numInitial
= "12345678900987654321.1234567896";
816 const char *numFormatted
= "12,345,678,900,987,654,321.12345679";
817 const char *parseExpected
= "12345678900987654321.12345679";
818 int32_t resultSize
= 0;
819 int32_t parsePos
= 0; /* Output parameter for Parse operations. */
820 #define DESTCAPACITY 100
821 UChar dest
[DESTCAPACITY
];
822 char desta
[DESTCAPACITY
];
823 UFieldPosition fieldPos
= {0};
827 status
= U_ZERO_ERROR
;
828 u_uastrcpy(dest
, bdpattern
);
829 fmt
= unum_open(UNUM_PATTERN_DECIMAL
, dest
, -1, "en", NULL
/*parseError*/, &status
);
830 if (U_FAILURE(status
)) log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
832 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, NULL
, &status
);
833 if (U_FAILURE(status
)) {
834 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
836 u_austrncpy(desta
, dest
, DESTCAPACITY
);
837 if (strcmp(numFormatted
, desta
) != 0) {
838 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
839 __FILE__
, __LINE__
, numFormatted
, desta
);
841 if (strlen(numFormatted
) != resultSize
) {
842 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
843 __FILE__
, __LINE__
, strlen(numFormatted
), resultSize
);
846 /* Format with a FieldPosition parameter */
848 fieldPos
.field
= UNUM_DECIMAL_SEPARATOR_FIELD
;
849 resultSize
= unum_formatDecimal(fmt
, numInitial
, -1, dest
, DESTCAPACITY
, &fieldPos
, &status
);
850 if (U_FAILURE(status
)) {
851 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
853 u_austrncpy(desta
, dest
, DESTCAPACITY
);
854 if (strcmp(numFormatted
, desta
) != 0) {
855 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
856 __FILE__
, __LINE__
, numFormatted
, desta
);
858 if (fieldPos
.beginIndex
!= 26) { /* index of "." in formatted number */
859 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
860 __FILE__
, __LINE__
, 0, fieldPos
.beginIndex
);
862 if (fieldPos
.endIndex
!= 27) {
863 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
864 __FILE__
, __LINE__
, 0, fieldPos
.endIndex
);
869 status
= U_ZERO_ERROR
;
870 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
871 resultSize
= unum_parseDecimal(fmt
, dest
, -1, NULL
, desta
, DESTCAPACITY
, &status
);
872 if (U_FAILURE(status
)) {
873 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
875 if (strcmp(parseExpected
, desta
) != 0) {
876 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
877 __FILE__
, __LINE__
, parseExpected
, desta
);
879 if (strlen(parseExpected
) != resultSize
) {
880 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
881 __FILE__
, __LINE__
, strlen(parseExpected
), resultSize
);
884 /* Parse with a parsePos parameter */
886 status
= U_ZERO_ERROR
;
887 u_uastrcpy(dest
, numFormatted
); /* Parse the expected output of the formatting test */
888 parsePos
= 3; /* 12,345,678,900,987,654,321.12345679 */
889 /* start parsing at the the third char */
890 resultSize
= unum_parseDecimal(fmt
, dest
, -1, &parsePos
, desta
, DESTCAPACITY
, &status
);
891 if (U_FAILURE(status
)) {
892 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
894 if (strcmp(parseExpected
+2, desta
) != 0) { /* "345678900987654321.12345679" */
895 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
896 __FILE__
, __LINE__
, parseExpected
+2, desta
);
898 if (strlen(numFormatted
) != parsePos
) {
899 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
900 __FILE__
, __LINE__
, strlen(parseExpected
), parsePos
);
906 status
= U_ZERO_ERROR
;
907 /* Test invalid symbol argument */
909 int32_t badsymbolLarge
= UNUM_FORMAT_SYMBOL_COUNT
+ 1;
910 int32_t badsymbolSmall
= -1;
912 int32_t valueLength
= 10;
913 UNumberFormat
*fmt
= unum_open(UNUM_DEFAULT
, NULL
, 0, NULL
, NULL
, &status
);
914 if (U_FAILURE(status
)) {
915 log_err("File %s, Line %d, status = %s\n", __FILE__
, __LINE__
, u_errorName(status
));
917 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, NULL
, 0, &status
);
918 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
920 status
= U_ZERO_ERROR
;
921 unum_getSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, NULL
, 0, &status
);
922 if (U_SUCCESS(status
)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
924 status
= U_ZERO_ERROR
;
925 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolLarge
, value
, valueLength
, &status
);
926 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
928 status
= U_ZERO_ERROR
;
929 unum_setSymbol(fmt
, (UNumberFormatSymbol
)badsymbolSmall
, value
, valueLength
, &status
);
930 if (U_SUCCESS(status
)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
937 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
944 unum_close(spellout_def
);
946 unum_close(cur_frpattern
);
951 static void TestParseZero(void)
953 UErrorCode errorCode
= U_ZERO_ERROR
;
954 UChar input
[] = {0x30, 0}; /* Input text is decimal '0' */
955 UChar pat
[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
959 UNumberFormat
* unum
= unum_open( UNUM_DECIMAL
/*or UNUM_DEFAULT*/, NULL
, -1, NULL
, NULL
, &errorCode
);
961 UNumberFormat
* unum
= unum_open( UNUM_PATTERN_DECIMAL
/*needs pattern*/, pat
, -1, NULL
, NULL
, &errorCode
);
964 dbl
= unum_parseDouble( unum
, input
, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode
);
965 if (U_FAILURE(errorCode
)) {
966 log_data_err("Result - %s\n", u_errorName(errorCode
));
968 log_verbose("Double: %f\n", dbl
);
973 static const UChar dollars2Sym
[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
974 static const UChar dollars4Sym
[] = { 0x24,0x34,0 }; /* $4 */
975 static const UChar dollars9Sym
[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
976 static const UChar pounds3Sym
[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
977 static const UChar pounds5Sym
[] = { 0xA3,0x35,0 }; /* [POUND]5 */
978 static const UChar pounds7Sym
[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
979 static const UChar euros4Sym
[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
980 static const UChar euros6Sym
[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
981 static const UChar euros8Sym
[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
982 static const UChar dollars4PluEn
[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
983 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 */
984 static const UChar euros8PluEn
[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
985 static const UChar euros6PluFr
[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
989 const char * descrip
;
990 const UChar
* currStr
;
991 const UChar
* plurStr
;
992 UErrorCode parsDoubExpectErr
;
993 int32_t parsDoubExpectPos
;
994 double parsDoubExpectVal
;
995 UErrorCode parsCurrExpectErr
;
996 int32_t parsCurrExpectPos
;
997 double parsCurrExpectVal
;
998 const char * parsCurrExpectCurr
;
1001 static const ParseCurrencyItem parseCurrencyItems
[] = {
1002 { "en_US", "dollars2", dollars2Sym
, NULL
, U_ZERO_ERROR
, 5, 2.0, U_ZERO_ERROR
, 5, 2.0, "USD" },
1003 { "en_US", "dollars4", dollars4Sym
, dollars4PluEn
, U_ZERO_ERROR
, 2, 4.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1004 { "en_US", "dollars9", dollars9Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1005 { "en_US", "pounds3", pounds3Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1006 { "en_US", "pounds5", pounds5Sym
, pounds5PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1007 { "en_US", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1008 { "en_US", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1010 { "en_GB", "pounds3", pounds3Sym
, NULL
, U_ZERO_ERROR
, 5, 3.0, U_ZERO_ERROR
, 5, 3.0, "GBP" },
1011 { "en_GB", "pounds5", pounds5Sym
, pounds5PluEn
, U_ZERO_ERROR
, 2, 5.0, U_ZERO_ERROR
, 2, 5.0, "GBP" },
1012 { "en_GB", "pounds7", pounds7Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1013 { "en_GB", "euros4", euros4Sym
, NULL
, U_PARSE_ERROR
, 4, 0.0, U_PARSE_ERROR
, 4, 0.0, "" },
1014 { "en_GB", "euros6", euros6Sym
, NULL
, U_PARSE_ERROR
, 1, 0.0, U_PARSE_ERROR
, 1, 0.0, "" },
1015 { "en_GB", "euros8", euros8Sym
, euros8PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 8.0, "EUR" },
1016 { "en_GB", "dollars4", dollars4Sym
, dollars4PluEn
, U_PARSE_ERROR
, 0, 0.0, U_ZERO_ERROR
, 2, 4.0, "USD" },
1018 { "fr_FR", "euros4", euros4Sym
, NULL
, U_ZERO_ERROR
, 6, 4.0, U_ZERO_ERROR
, 6, 4.0, "EUR" },
1019 { "fr_FR", "euros6", euros6Sym
, euros6PluFr
, U_ZERO_ERROR
, 3, 6.0, U_ZERO_ERROR
, 3, 6.0, "EUR" },
1020 { "fr_FR", "euros8", euros8Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1021 { "fr_FR", "dollars2", dollars2Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1022 { "fr_FR", "dollars4", dollars4Sym
, NULL
, U_PARSE_ERROR
, 0, 0.0, U_PARSE_ERROR
, 0, 0.0, "" },
1024 { NULL
, NULL
, NULL
, NULL
, 0, 0, 0.0, 0, 0, 0.0, NULL
}
1027 static void TestParseCurrency()
1029 const ParseCurrencyItem
* itemPtr
;
1030 for (itemPtr
= parseCurrencyItems
; itemPtr
->locale
!= NULL
; ++itemPtr
) {
1031 UNumberFormat
* unum
;
1038 status
= U_ZERO_ERROR
;
1039 unum
= unum_open(UNUM_CURRENCY
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1040 if (U_SUCCESS(status
)) {
1041 status
= U_ZERO_ERROR
;
1043 parseVal
= unum_parseDouble(unum
, itemPtr
->currStr
, -1, &parsePos
, &status
);
1044 if (status
!= itemPtr
->parsDoubExpectErr
|| parsePos
!= itemPtr
->parsDoubExpectPos
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1045 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1046 itemPtr
->locale
, itemPtr
->descrip
,
1047 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectPos
, itemPtr
->parsDoubExpectVal
,
1048 u_errorName(status
), parsePos
, parseVal
);
1050 status
= U_ZERO_ERROR
;
1053 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->currStr
, -1, &parsePos
, parseCurr
, &status
);
1054 u_austrncpy(parseCurrB
, parseCurr
, 4);
1055 if (status
!= itemPtr
->parsCurrExpectErr
|| parsePos
!= itemPtr
->parsCurrExpectPos
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1056 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1057 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1058 itemPtr
->locale
, itemPtr
->descrip
,
1059 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectPos
, itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1060 u_errorName(status
), parsePos
, parseVal
, parseCurrB
);
1064 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1068 /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */
1069 if (itemPtr
->plurStr
!= NULL
) {
1070 status
= U_ZERO_ERROR
;
1071 unum
= unum_open(UNUM_CURRENCY_PLURAL
, NULL
, 0, itemPtr
->locale
, NULL
, &status
);
1072 if (U_SUCCESS(status
)) {
1073 status
= U_ZERO_ERROR
;
1075 parseVal
= unum_parseDouble(unum
, itemPtr
->plurStr
, -1, &parsePos
, &status
);
1076 if (status
!= itemPtr
->parsDoubExpectErr
|| parseVal
!= itemPtr
->parsDoubExpectVal
) {
1077 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
1078 itemPtr
->locale
, itemPtr
->descrip
,
1079 u_errorName(itemPtr
->parsDoubExpectErr
), itemPtr
->parsDoubExpectVal
,
1080 u_errorName(status
), parseVal
);
1082 status
= U_ZERO_ERROR
;
1085 parseVal
= unum_parseDoubleCurrency(unum
, itemPtr
->plurStr
, -1, &parsePos
, parseCurr
, &status
);
1086 u_austrncpy(parseCurrB
, parseCurr
, 4);
1087 if (status
!= itemPtr
->parsCurrExpectErr
|| parseVal
!= itemPtr
->parsCurrExpectVal
||
1088 strncmp(parseCurrB
, itemPtr
->parsCurrExpectCurr
, 4) != 0) {
1089 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1090 itemPtr
->locale
, itemPtr
->descrip
,
1091 u_errorName(itemPtr
->parsCurrExpectErr
), itemPtr
->parsCurrExpectVal
, itemPtr
->parsCurrExpectCurr
,
1092 u_errorName(status
), parseVal
, parseCurrB
);
1096 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr
->locale
, u_errorName(status
));
1104 const char * testname
;
1105 const char * locale
;
1107 const UChar
* source
;
1114 static const UChar ustr_zh50d
[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1115 static const UChar ustr_zh05a
[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1116 static const UChar ustr_zh05d
[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1118 static const NumParseTestItem altnumParseTests
[] = {
1119 /* name loc lenent src start val end status */
1120 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1121 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1122 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1123 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1126 static void TestParseAltNum(void)
1128 const NumParseTestItem
* testPtr
;
1129 for (testPtr
= altnumParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1130 UErrorCode status
= U_ZERO_ERROR
;
1131 int32_t value
, position
= testPtr
->startPos
;
1132 UNumberFormat
*nf
= unum_open(UNUM_DECIMAL
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1133 if (U_FAILURE(status
)) {
1134 log_err_status(status
, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1137 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1138 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1139 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1140 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1141 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1142 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1143 value
, position
, myErrorName(status
) );
1149 static const UChar ustr_en0
[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1150 static const UChar ustr_123
[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1151 static const UChar ustr_en123
[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1152 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1153 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1154 static const UChar ustr_fr123
[] = {0x63, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1155 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent-vingt-trois */
1156 static const UChar ustr_ja123
[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1157 static const UChar ustr_zh50s
[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1158 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1159 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1160 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1162 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1164 static const NumParseTestItem spelloutParseTests
[] = {
1165 /* name loc lenent src start val end status */
1166 { "en0", "en", FALSE
, ustr_en0
, 0, 0, 4, U_ZERO_ERROR
},
1167 { "en0", "en", FALSE
, ustr_en0
, 2, 0, 2, U_PARSE_ERROR
},
1168 { "en0", "ja", FALSE
, ustr_en0
, 0, 0, 0, U_PARSE_ERROR
},
1169 #if NUMERIC_STRINGS_NOT_PARSEABLE
1170 { "123", "en", FALSE
, ustr_123
, 0, 0, 0, U_PARSE_ERROR
},
1172 { "123", "en", FALSE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1174 { "123L", "en", TRUE
, ustr_123
, 0, 123, 3, U_ZERO_ERROR
},
1175 { "en123", "en", FALSE
, ustr_en123
, 0, 123, 24, U_ZERO_ERROR
},
1176 { "en123", "en", FALSE
, ustr_en123
, 12, 23, 24, U_ZERO_ERROR
},
1177 { "en123", "fr", FALSE
, ustr_en123
, 16, 0, 16, U_PARSE_ERROR
},
1178 { "fr123", "fr", FALSE
, ustr_fr123
, 0, 123, 16, U_ZERO_ERROR
},
1179 { "fr123", "fr", FALSE
, ustr_fr123
, 5, 23, 16, U_ZERO_ERROR
},
1180 { "fr123", "en", FALSE
, ustr_fr123
, 0, 0, 0, U_PARSE_ERROR
},
1181 { "ja123", "ja", FALSE
, ustr_ja123
, 0, 123, 4, U_ZERO_ERROR
},
1182 { "ja123", "ja", FALSE
, ustr_ja123
, 1, 23, 4, U_ZERO_ERROR
},
1183 { "ja123", "fr", FALSE
, ustr_ja123
, 0, 0, 0, U_PARSE_ERROR
},
1184 { "zh,50s", "zh", FALSE
, ustr_zh50s
, 0, 50, 2, U_ZERO_ERROR
},
1185 #if NUMERIC_STRINGS_NOT_PARSEABLE
1186 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1187 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1188 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1190 { "zh@hd,50d", "zh@numbers=hanidec", FALSE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1191 { "zh@hd,05a", "zh@numbers=hanidec", FALSE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1192 { "zh@hd,05d", "zh@numbers=hanidec", FALSE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1194 { "zh@hd,50dL","zh@numbers=hanidec", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
},
1195 { "zh@hd,05aL","zh@numbers=hanidec", TRUE
, ustr_zh05a
, 0, 5, 2, U_ZERO_ERROR
},
1196 { "zh@hd,05dL","zh@numbers=hanidec", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
},
1197 { "zh,50dL","zh", TRUE
, ustr_zh50d
, 0, 50, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1198 { "zh,05aL","zh", TRUE
, ustr_zh05a
, 0, 0, 1, U_ZERO_ERROR
},
1199 { "zh,05dL","zh", TRUE
, ustr_zh05d
, 0, 5, 2, U_ZERO_ERROR
}, /* changed in ICU50m2 */
1200 { NULL
, NULL
, FALSE
, NULL
, 0, 0, 0, 0 } /* terminator */
1203 static void TestSpelloutNumberParse()
1205 const NumParseTestItem
* testPtr
;
1206 for (testPtr
= spelloutParseTests
; testPtr
->testname
!= NULL
; ++testPtr
) {
1207 UErrorCode status
= U_ZERO_ERROR
;
1208 int32_t value
, position
= testPtr
->startPos
;
1209 UNumberFormat
*nf
= unum_open(UNUM_SPELLOUT
, NULL
, 0, testPtr
->locale
, NULL
, &status
);
1210 if (U_FAILURE(status
)) {
1211 log_err_status(status
, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr
->locale
, myErrorName(status
));
1214 unum_setAttribute(nf
, UNUM_LENIENT_PARSE
, testPtr
->lenient
);
1215 value
= unum_parse(nf
, testPtr
->source
, -1, &position
, &status
);
1216 if ( value
!= testPtr
->value
|| position
!= testPtr
->endPos
|| status
!= testPtr
->status
) {
1217 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1218 testPtr
->locale
, testPtr
->testname
, testPtr
->startPos
,
1219 testPtr
->value
, testPtr
->endPos
, myErrorName(testPtr
->status
),
1220 value
, position
, myErrorName(status
) );
1226 static void TestSignificantDigits()
1229 int32_t resultlengthneeded
;
1230 int32_t resultlength
;
1231 UErrorCode status
= U_ZERO_ERROR
;
1232 UChar
*result
= NULL
;
1234 double d
= 123456.789;
1236 u_uastrcpy(temp
, "###0.0#");
1237 fmt
=unum_open(UNUM_IGNORE
, temp
, -1, NULL
, NULL
,&status
);
1238 if (U_FAILURE(status
)) {
1239 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1242 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1243 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 6);
1245 u_uastrcpy(temp
, "123457");
1247 resultlengthneeded
=unum_formatDouble(fmt
, d
, NULL
, resultlength
, NULL
, &status
);
1248 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1250 status
=U_ZERO_ERROR
;
1251 resultlength
=resultlengthneeded
+1;
1252 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1253 unum_formatDouble(fmt
, d
, result
, resultlength
, NULL
, &status
);
1255 if(U_FAILURE(status
))
1257 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1260 if(u_strcmp(result
, temp
)==0)
1261 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1263 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1268 static void TestSigDigRounding()
1270 UErrorCode status
= U_ZERO_ERROR
;
1271 UChar expected
[128];
1278 fmt
=unum_open(UNUM_DECIMAL
, NULL
, 0, NULL
/* "en_US"*/, NULL
, &status
);
1279 if (U_FAILURE(status
)) {
1280 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status
));
1283 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, FALSE
);
1284 unum_setAttribute(fmt
, UNUM_SIGNIFICANT_DIGITS_USED
, TRUE
);
1285 unum_setAttribute(fmt
, UNUM_MAX_SIGNIFICANT_DIGITS
, 2);
1286 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1288 unum_setAttribute(fmt
, UNUM_ROUNDING_MODE
, UNUM_ROUND_UP
);
1289 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, 20.0);
1291 (void)unum_formatDouble(fmt
, d
, result
, sizeof(result
) / sizeof(result
[0]), NULL
, &status
);
1292 if(U_FAILURE(status
))
1294 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status
));
1298 u_uastrcpy(expected
, "140");
1299 if(u_strcmp(result
, expected
)!=0)
1300 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1
, result
), u_austrcpy(temp2
, expected
) );
1305 static void TestNumberFormatPadding()
1310 UErrorCode status
=U_ZERO_ERROR
;
1311 int32_t resultlength
;
1312 int32_t resultlengthneeded
;
1313 UNumberFormat
*pattern
;
1315 double d
= -10456.37;
1316 UFieldPosition pos1
;
1319 /* create a number format using unum_openPattern(....)*/
1320 log_verbose("\nTesting unum_openPattern() with padding\n");
1321 u_uastrcpy(temp1
, "*#,##0.0#*;(#,##0.0#)");
1322 status
=U_ZERO_ERROR
;
1323 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), NULL
, NULL
,&status
);
1324 if(U_SUCCESS(status
))
1326 log_err("error in unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );
1330 unum_close(pattern
);
1333 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1334 u_uastrcpy(temp1
, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
1335 status
=U_ZERO_ERROR
;
1336 pattern
=unum_open(UNUM_IGNORE
,temp1
, u_strlen(temp1
), "en_US",NULL
, &status
);
1337 if(U_FAILURE(status
))
1339 log_err_status(status
, "error in padding unum_openPattern(%s): %s\n", temp1
, myErrorName(status
) );;
1342 log_verbose("Pass: padding unum_openPattern() works fine\n");
1344 /*test for unum_toPattern()*/
1345 log_verbose("\nTesting padding unum_toPattern()\n");
1347 resultlengthneeded
=unum_toPattern(pattern
, FALSE
, NULL
, resultlength
, &status
);
1348 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1350 status
=U_ZERO_ERROR
;
1351 resultlength
=resultlengthneeded
+1;
1352 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1353 unum_toPattern(pattern
, FALSE
, result
, resultlength
, &status
);
1355 if(U_FAILURE(status
))
1357 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status
));
1361 if(u_strcmp(result
, temp1
)!=0)
1362 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
1364 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1367 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1368 u_uastrcpy(temp1
, "xxxxx(10,456.37)");
1370 pos1
.field
= UNUM_FRACTION_FIELD
;
1371 resultlengthneeded
=unum_formatDouble(pattern
, d
, NULL
, resultlength
, &pos1
, &status
);
1372 if(status
==U_BUFFER_OVERFLOW_ERROR
)
1374 status
=U_ZERO_ERROR
;
1375 resultlength
=resultlengthneeded
+1;
1376 result
=(UChar
*)malloc(sizeof(UChar
) * resultlength
);
1377 unum_formatDouble(pattern
, d
, result
, resultlength
, NULL
, &status
);
1379 if(U_FAILURE(status
))
1381 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status
));
1385 if(u_strcmp(result
, temp1
)==0)
1386 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1388 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1389 if(pos1
.beginIndex
== 13 && pos1
.endIndex
== 15)
1390 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1392 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1393 pos1
.beginIndex
, pos1
.endIndex
);
1396 /* Testing unum_parse() and unum_parseDouble() */
1397 log_verbose("\nTesting padding unum_parseDouble()\n");
1399 d1
=unum_parseDouble(pattern
, result
, u_strlen(result
), &parsepos
, &status
);
1400 if(U_FAILURE(status
))
1402 log_err("padding parse failed. The error is : %s\n", myErrorName(status
));
1406 log_err("Fail: Error in padding parsing\n");
1408 log_verbose("Pass: padding parsing successful\n");
1413 unum_close(pattern
);
1417 withinErr(double a
, double b
, double err
) {
1418 return uprv_fabs(a
- b
) < uprv_fabs(a
* err
);
1421 static void TestInt64Format() {
1425 UErrorCode status
= U_ZERO_ERROR
;
1426 const double doubleInt64Max
= (double)U_INT64_MAX
;
1427 const double doubleInt64Min
= (double)U_INT64_MIN
;
1428 const double doubleBig
= 10.0 * (double)U_INT64_MAX
;
1434 /* create a number format using unum_openPattern(....) */
1435 log_verbose("\nTesting Int64Format\n");
1436 u_uastrcpy(temp1
, "#.#E0");
1437 fmt
= unum_open(UNUM_IGNORE
, temp1
, u_strlen(temp1
), NULL
, NULL
, &status
);
1438 if(U_FAILURE(status
)) {
1439 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status
));
1441 unum_setAttribute(fmt
, UNUM_MAX_FRACTION_DIGITS
, 20);
1442 unum_formatInt64(fmt
, U_INT64_MAX
, result
, 512, NULL
, &status
);
1443 if (U_FAILURE(status
)) {
1444 log_err("error in unum_format(): %s\n", myErrorName(status
));
1446 log_verbose("format int64max: '%s'\n", result
);
1448 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1449 if (status
!= U_INVALID_FORMAT_ERROR
) {
1450 log_err("parse didn't report error: %s\n", myErrorName(status
));
1451 } else if (val32
!= INT32_MAX
) {
1452 log_err("parse didn't pin return value, got: %d\n", val32
);
1455 status
= U_ZERO_ERROR
;
1457 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1458 if (U_FAILURE(status
)) {
1459 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1460 } else if (val64
!= U_INT64_MAX
) {
1461 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1464 status
= U_ZERO_ERROR
;
1466 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1467 if (U_FAILURE(status
)) {
1468 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1469 } else if (valDouble
!= doubleInt64Max
) {
1470 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1474 unum_formatInt64(fmt
, U_INT64_MIN
, result
, 512, NULL
, &status
);
1475 if (U_FAILURE(status
)) {
1476 log_err("error in unum_format(): %s\n", myErrorName(status
));
1478 log_verbose("format int64min: '%s'\n", result
);
1480 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1481 if (status
!= U_INVALID_FORMAT_ERROR
) {
1482 log_err("parse didn't report error: %s\n", myErrorName(status
));
1483 } else if (val32
!= INT32_MIN
) {
1484 log_err("parse didn't pin return value, got: %d\n", val32
);
1487 status
= U_ZERO_ERROR
;
1489 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1490 if (U_FAILURE(status
)) {
1491 log_err("parseInt64 returned error: %s\n", myErrorName(status
));
1492 } else if (val64
!= U_INT64_MIN
) {
1493 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1496 status
= U_ZERO_ERROR
;
1498 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1499 if (U_FAILURE(status
)) {
1500 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1501 } else if (valDouble
!= doubleInt64Min
) {
1502 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1506 unum_formatDouble(fmt
, doubleBig
, result
, 512, NULL
, &status
);
1507 if (U_FAILURE(status
)) {
1508 log_err("error in unum_format(): %s\n", myErrorName(status
));
1510 log_verbose("format doubleBig: '%s'\n", result
);
1512 val32
= unum_parse(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1513 if (status
!= U_INVALID_FORMAT_ERROR
) {
1514 log_err("parse didn't report error: %s\n", myErrorName(status
));
1515 } else if (val32
!= INT32_MAX
) {
1516 log_err("parse didn't pin return value, got: %d\n", val32
);
1519 status
= U_ZERO_ERROR
;
1521 val64
= unum_parseInt64(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1522 if (status
!= U_INVALID_FORMAT_ERROR
) {
1523 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status
));
1524 } else if (val64
!= U_INT64_MAX
) {
1525 log_err("parseInt64 returned incorrect value, got: %ld\n", val64
);
1528 status
= U_ZERO_ERROR
;
1530 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1531 if (U_FAILURE(status
)) {
1532 log_err("parseDouble returned error: %s\n", myErrorName(status
));
1533 } else if (!withinErr(valDouble
, doubleBig
, 1e-15)) {
1534 log_err("parseDouble returned incorrect value, got: %g\n", valDouble
);
1538 u_uastrcpy(result
, "5.06e-27");
1540 valDouble
= unum_parseDouble(fmt
, result
, u_strlen(result
), &parsepos
, &status
);
1541 if (U_FAILURE(status
)) {
1542 log_err("parseDouble() returned error: %s\n", myErrorName(status
));
1543 } else if (!withinErr(valDouble
, 5.06e-27, 1e-15)) {
1544 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble
);
1551 static void test_fmt(UNumberFormat
* fmt
, UBool isDecimal
) {
1554 int32_t BUFSIZE
= sizeof(buffer
)/sizeof(buffer
[0]);
1556 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1560 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1561 UErrorCode status
= U_ZERO_ERROR
;
1562 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1563 if (U_FAILURE(status
)) {
1564 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1566 u_austrcpy(temp
, buffer
);
1567 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1571 /* check APIs now */
1573 UErrorCode status
= U_ZERO_ERROR
;
1575 u_uastrcpy(buffer
, "#,##0.0#");
1576 unum_applyPattern(fmt
, FALSE
, buffer
, -1, &perr
, &status
);
1577 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1578 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status
));
1583 int isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1584 log_verbose("lenient: 0x%x\n", isLenient
);
1585 if (isLenient
!= FALSE
) {
1586 log_err("didn't expect lenient value: %d\n", isLenient
);
1589 unum_setAttribute(fmt
, UNUM_LENIENT_PARSE
, TRUE
);
1590 isLenient
= unum_getAttribute(fmt
, UNUM_LENIENT_PARSE
);
1591 if (isLenient
!= TRUE
) {
1592 log_err("didn't expect lenient value after set: %d\n", isLenient
);
1598 double val
= unum_getDoubleAttribute(fmt
, UNUM_LENIENT_PARSE
);
1600 log_err("didn't expect double attribute\n");
1602 val
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1603 if ((val
== -1) == isDecimal
) {
1604 log_err("didn't expect -1 rounding increment\n");
1606 unum_setDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
, val
+.5);
1607 val2
= unum_getDoubleAttribute(fmt
, UNUM_ROUNDING_INCREMENT
);
1608 if (isDecimal
&& (val2
- val
!= .5)) {
1609 log_err("set rounding increment had no effect on decimal format");
1614 UErrorCode status
= U_ZERO_ERROR
;
1615 int len
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1616 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1617 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status
));
1619 if (U_SUCCESS(status
)) {
1620 u_austrcpy(temp
, buffer
);
1621 log_verbose("default ruleset: '%s'\n", temp
);
1624 status
= U_ZERO_ERROR
;
1625 len
= unum_getTextAttribute(fmt
, UNUM_PUBLIC_RULESETS
, buffer
, BUFSIZE
, &status
);
1626 if (isDecimal
? (status
!= U_UNSUPPORTED_ERROR
) : U_FAILURE(status
)) {
1627 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status
));
1629 if (U_SUCCESS(status
)) {
1630 u_austrcpy(temp
, buffer
);
1631 log_verbose("public rulesets: '%s'\n", temp
);
1633 /* set the default ruleset to the first one found, and retry */
1636 for (i
= 0; i
< len
&& temp
[i
] != ';'; ++i
){};
1639 unum_setTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, -1, &status
);
1640 if (U_FAILURE(status
)) {
1641 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status
));
1643 int len2
= unum_getTextAttribute(fmt
, UNUM_DEFAULT_RULESET
, buffer
, BUFSIZE
, &status
);
1644 if (U_FAILURE(status
)) {
1645 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status
));
1646 } else if (len2
!= i
) {
1647 u_austrcpy(temp
, buffer
);
1648 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2
, i
, temp
);
1650 for (i
= 0; i
< sizeof(vals
)/sizeof(vals
[0]); ++i
) {
1651 status
= U_ZERO_ERROR
;
1652 unum_formatDouble(fmt
, vals
[i
], buffer
, BUFSIZE
, NULL
, &status
);
1653 if (U_FAILURE(status
)) {
1654 log_err("failed to format: %g, returned %s\n", vals
[i
], u_errorName(status
));
1656 u_austrcpy(temp
, buffer
);
1657 log_verbose("formatting %g returned '%s'\n", vals
[i
], temp
);
1668 UErrorCode status
= U_ZERO_ERROR
;
1669 unum_toPattern(fmt
, FALSE
, buffer
, BUFSIZE
, &status
);
1670 if (U_SUCCESS(status
)) {
1671 u_austrcpy(temp
, buffer
);
1672 log_verbose("pattern: '%s'\n", temp
);
1673 } else if (status
!= U_BUFFER_OVERFLOW_ERROR
) {
1674 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status
));
1676 log_verbose("pattern too long to display\n");
1681 UErrorCode status
= U_ZERO_ERROR
;
1682 int len
= unum_getSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, BUFSIZE
, &status
);
1683 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1684 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status
));
1687 unum_setSymbol(fmt
, UNUM_CURRENCY_SYMBOL
, buffer
, len
, &status
);
1688 if (isDecimal
? U_FAILURE(status
) : (status
!= U_UNSUPPORTED_ERROR
)) {
1689 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status
));
1694 static void TestNonExistentCurrency() {
1695 UNumberFormat
*format
;
1696 UErrorCode status
= U_ZERO_ERROR
;
1697 UChar currencySymbol
[8];
1698 static const UChar QQQ
[] = {0x51, 0x51, 0x51, 0};
1700 /* Get a non-existent currency and make sure it returns the correct currency code. */
1701 format
= unum_open(UNUM_CURRENCY
, NULL
, 0, "th_TH@currency=QQQ", NULL
, &status
);
1702 if (format
== NULL
|| U_FAILURE(status
)) {
1703 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status
));
1706 unum_getSymbol(format
,
1707 UNUM_CURRENCY_SYMBOL
,
1709 sizeof(currencySymbol
)/sizeof(currencySymbol
[0]),
1711 if (u_strcmp(currencySymbol
, QQQ
) != 0) {
1712 log_err("unum_open set the currency to QQQ\n");
1718 static void TestRBNFFormat() {
1722 UChar tempUChars
[512];
1723 UNumberFormat
*formats
[5];
1724 int COUNT
= sizeof(formats
)/sizeof(formats
[0]);
1727 for (i
= 0; i
< COUNT
; ++i
) {
1732 status
= U_ZERO_ERROR
;
1733 u_uastrcpy(pat
, "#,##0.0#;(#,##0.0#)");
1734 formats
[0] = unum_open(UNUM_PATTERN_DECIMAL
, pat
, -1, "en_US", &perr
, &status
);
1735 if (U_FAILURE(status
)) {
1736 log_err_status(status
, "unable to open decimal pattern -> %s\n", u_errorName(status
));
1740 status
= U_ZERO_ERROR
;
1741 formats
[1] = unum_open(UNUM_SPELLOUT
, NULL
, 0, "en_US", &perr
, &status
);
1742 if (U_FAILURE(status
)) {
1743 log_err_status(status
, "unable to open spellout -> %s\n", u_errorName(status
));
1747 status
= U_ZERO_ERROR
;
1748 formats
[2] = unum_open(UNUM_ORDINAL
, NULL
, 0, "en_US", &perr
, &status
);
1749 if (U_FAILURE(status
)) {
1750 log_err_status(status
, "unable to open ordinal -> %s\n", u_errorName(status
));
1754 status
= U_ZERO_ERROR
;
1755 formats
[3] = unum_open(UNUM_DURATION
, NULL
, 0, "en_US", &perr
, &status
);
1756 if (U_FAILURE(status
)) {
1757 log_err_status(status
, "unable to open duration %s\n", u_errorName(status
));
1761 status
= U_ZERO_ERROR
;
1765 "x.x: << point >>;\n"
1766 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1767 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1768 "seventeen; eighteen; nineteen;\n"
1769 "20: twenty[->>];\n"
1770 "30: thirty[->>];\n"
1774 "70: seventy[->>];\n"
1775 "80: eighty[->>];\n"
1776 "90: ninety[->>];\n"
1778 u_uastrcpy(tempUChars
,
1781 "20: twenty[ and change];\n"
1782 "30: thirty[ and change];\n"
1783 "40: forty[ and change];\n"
1784 "50: fifty[ and change];\n"
1785 "60: sixty[ and change];\n"
1786 "70: seventy[ and change];\n"
1787 "80: eighty[ and change];\n"
1788 "90: ninety[ and change];\n"
1792 "x.x: << point something;\n"
1794 "20: some reasonable number;\n"
1795 "100: some substantial number;\n"
1796 "100,000,000: some huge number;\n");
1797 /* This is to get around some compiler warnings about char * string length. */
1798 u_strcat(pat
, tempUChars
);
1799 formats
[4] = unum_open(UNUM_PATTERN_RULEBASED
, pat
, -1, "en_US", &perr
, &status
);
1800 if (U_FAILURE(status
)) {
1801 log_err_status(status
, "unable to open rulebased pattern -> %s\n", u_errorName(status
));
1803 if (U_FAILURE(status
)) {
1804 log_err_status(status
, "Something failed with %s\n", u_errorName(status
));
1808 for (i
= 0; i
< COUNT
; ++i
) {
1809 log_verbose("\n\ntesting format %d\n", i
);
1810 test_fmt(formats
[i
], (UBool
)(i
== 0));
1813 #define FORMAT_BUF_CAPACITY 64
1815 UChar fmtbuf
[FORMAT_BUF_CAPACITY
];
1817 double nanvalue
= uprv_getNaN();
1818 status
= U_ZERO_ERROR
;
1819 len
= unum_formatDouble(formats
[1], nanvalue
, fmtbuf
, FORMAT_BUF_CAPACITY
, NULL
, &status
);
1820 if (U_FAILURE(status
)) {
1821 log_err_status(status
, "unum_formatDouble NAN failed with %s\n", u_errorName(status
));
1823 UChar nansym
[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1824 if ( len
!= 3 || u_strcmp(fmtbuf
, nansym
) != 0 ) {
1825 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1830 for (i
= 0; i
< COUNT
; ++i
) {
1831 unum_close(formats
[i
]);
1835 static void TestCurrencyRegression(void) {
1837 I've found a case where unum_parseDoubleCurrency is not doing what I
1838 expect. The value I pass in is $1234567890q123460000.00 and this
1839 returns with a status of zero error & a parse pos of 22 (I would
1840 expect a parse error at position 11).
1842 I stepped into DecimalFormat::subparse() and it looks like it parses
1843 the first 10 digits and then stops parsing at the q but doesn't set an
1844 error. Then later in DecimalFormat::parse() the value gets crammed
1845 into a long (which greatly truncates the value).
1847 This is very problematic for me 'cause I try to remove chars that are
1848 invalid but this allows my users to enter bad chars and truncates
1858 UErrorCode status
= U_ZERO_ERROR
;
1859 const int32_t expected
= 11;
1862 u_uastrcpy(buf
, "$1234567890q643210000.00");
1863 cur
= unum_open(UNUM_CURRENCY
, NULL
,0,"en_US", NULL
, &status
);
1865 if(U_FAILURE(status
)) {
1866 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status
));
1870 status
= U_ZERO_ERROR
; /* so we can test it later. */
1873 d
= unum_parseDoubleCurrency(cur
,
1876 &pos
, /* 0 = start */
1880 u_austrcpy(acurrency
, currency
);
1882 if(U_FAILURE(status
) || (pos
!= expected
)) {
1883 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1884 expected
, d
, u_errorName(status
), pos
, acurrency
);
1886 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d
, u_errorName(status
), pos
, acurrency
);
1892 static void TestTextAttributeCrash(void) {
1893 UChar ubuffer
[64] = {0x0049,0x004E,0x0052,0};
1894 static const UChar expectedNeg
[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1895 static const UChar expectedPos
[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1897 UErrorCode status
= U_ZERO_ERROR
;
1898 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, "en_US", NULL
, &status
);
1899 if (U_FAILURE(status
)) {
1900 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status
));
1903 unum_setTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, 3, &status
);
1905 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1906 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1908 used
= unum_getTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, 64, &status
);
1909 unum_setTextAttribute(nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, used
, &status
);
1910 if (U_FAILURE(status
)) {
1911 log_err("FAILED 2\n"); exit(1);
1913 log_verbose("attempting to format...\n");
1914 used
= unum_formatDouble(nf
, -1234.5, ubuffer
, 64, NULL
, &status
);
1915 if (U_FAILURE(status
) || 64 < used
) {
1916 log_err("Failed formatting %s\n", u_errorName(status
));
1919 if (u_strcmp(expectedNeg
, ubuffer
) == 0) {
1920 log_err("Didn't get expected negative result\n");
1922 used
= unum_formatDouble(nf
, 1234.5, ubuffer
, 64, NULL
, &status
);
1923 if (U_FAILURE(status
) || 64 < used
) {
1924 log_err("Failed formatting %s\n", u_errorName(status
));
1927 if (u_strcmp(expectedPos
, ubuffer
) == 0) {
1928 log_err("Didn't get expected positive result\n");
1933 static void TestNBSPPatternRtNum(const char *testcase
, int line
, UNumberFormat
*nf
, double myNumber
) {
1934 UErrorCode status
= U_ZERO_ERROR
;
1937 double aNumber
= -1.0;
1938 unum_formatDouble(nf
, myNumber
, myString
, 20, NULL
, &status
);
1939 log_verbose("%s:%d: formatted %.2f into %s\n", testcase
, line
, myNumber
, u_austrcpy(tmpbuf
, myString
));
1940 if(U_FAILURE(status
)) {
1941 log_err("%s:%d: failed format of %.2g with %s\n", testcase
, line
, myNumber
, u_errorName(status
));
1944 aNumber
= unum_parse(nf
, myString
, -1, NULL
, &status
);
1945 if(U_FAILURE(status
)) {
1946 log_err("%s:%d: failed parse with %s\n", testcase
, line
, u_errorName(status
));
1949 if(uprv_fabs(aNumber
-myNumber
)>.001) {
1950 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
1952 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase
, line
, myNumber
, aNumber
);
1956 static void TestNBSPPatternRT(const char *testcase
, UNumberFormat
*nf
) {
1957 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, 12345.);
1958 TestNBSPPatternRtNum(testcase
, __LINE__
, nf
, -12345.);
1961 static void TestNBSPInPattern(void) {
1962 UErrorCode status
= U_ZERO_ERROR
;
1963 UNumberFormat
* nf
= NULL
;
1964 const char *testcase
;
1967 testcase
="ar_AE UNUM_CURRENCY";
1968 nf
= unum_open(UNUM_CURRENCY
, NULL
, -1, "ar_AE", NULL
, &status
);
1969 if(U_FAILURE(status
) || nf
== NULL
) {
1970 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, testcase
, u_errorName(status
));
1973 TestNBSPPatternRT(testcase
, nf
);
1975 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
1977 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
1979 testcase
= "ar_AE special pattern: " SPECIAL_PATTERN
;
1980 u_unescape(SPECIAL_PATTERN
, pat
, sizeof(pat
)/sizeof(pat
[0]));
1981 unum_applyPattern(nf
, FALSE
, pat
, -1, NULL
, &status
);
1982 if(U_FAILURE(status
)) {
1983 log_err("%s: unum_applyPattern failed with %s\n", testcase
, u_errorName(status
));
1985 TestNBSPPatternRT(testcase
, nf
);
1987 #undef SPECIAL_PATTERN
1989 unum_close(nf
); status
= U_ZERO_ERROR
;
1991 testcase
="ar_AE UNUM_DECIMAL";
1992 nf
= unum_open(UNUM_DECIMAL
, NULL
, -1, "ar_AE", NULL
, &status
);
1993 if(U_FAILURE(status
)) {
1994 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
1996 TestNBSPPatternRT(testcase
, nf
);
1997 unum_close(nf
); status
= U_ZERO_ERROR
;
1999 testcase
="ar_AE UNUM_PERCENT";
2000 nf
= unum_open(UNUM_PERCENT
, NULL
, -1, "ar_AE", NULL
, &status
);
2001 if(U_FAILURE(status
)) {
2002 log_err("%s: unum_open failed with %s\n", testcase
, u_errorName(status
));
2004 TestNBSPPatternRT(testcase
, nf
);
2005 unum_close(nf
); status
= U_ZERO_ERROR
;
2010 static void TestCloneWithRBNF(void) {
2011 UChar pattern
[1024];
2013 UErrorCode status
= U_ZERO_ERROR
;
2015 UChar buffer_cloned
[256];
2018 UNumberFormat
*pform_cloned
;
2019 UNumberFormat
*pform
;
2023 "0.x: >%%millis-only>;\n"
2024 "x.0: <%%duration<;\n"
2025 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2026 "-x: ->>;%%millis-only:\n"
2027 "1000: 00:00.<%%millis<;\n"
2029 "1000: .<%%millis<;\n"
2033 "0: =%%seconds-only=;\n"
2034 "60: =%%min-sec=;\n"
2035 "3600: =%%hr-min-sec=;\n"
2036 "86400/86400: <%%ddaayyss<[, >>];\n"
2037 "%%durationwithmillis:\n"
2038 "0: =%%seconds-only=;\n"
2039 "60: =%%min-sec=;\n"
2040 "3600: =%%hr-min-sec=;\n"
2041 "86400/86400: <%%ddaayyss<, >>;\n");
2051 "3600/60: <0<:>>>;\n"
2057 /* This is to get around some compiler warnings about char * string length. */
2058 u_strcat(pattern
, pat2
);
2060 pform
= unum_open(UNUM_PATTERN_RULEBASED
, pattern
, -1, "en_US", NULL
, &status
);
2061 unum_formatDouble(pform
, 3600, buffer
, 256, NULL
, &status
);
2063 pform_cloned
= unum_clone(pform
,&status
);
2064 unum_formatDouble(pform_cloned
, 3600, buffer_cloned
, 256, NULL
, &status
);
2067 unum_close(pform_cloned
);
2069 if (u_strcmp(buffer
,buffer_cloned
)) {
2070 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
));
2075 static void TestNoExponent(void) {
2076 UErrorCode status
= U_ZERO_ERROR
;
2084 fmt
= unum_open(UNUM_DECIMAL
, NULL
, -1, "en_US", NULL
, &status
);
2086 if(U_FAILURE(status
) || fmt
== NULL
) {
2087 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
));
2092 u_uastrcpy(str
, cstr
);
2095 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2096 ASSERT_TRUE(pos
==4);
2097 if(U_FAILURE(status
)) {
2098 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2099 } else if(expect
!=num
) {
2100 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2102 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2105 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2107 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2108 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2110 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2114 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2116 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__
, __LINE__
, cstr
);
2117 } else if(num
==expect
) {
2118 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__
, __LINE__
, num
, cstr
);
2120 ASSERT_TRUE(pos
==2);
2122 status
= U_ZERO_ERROR
;
2126 /* ok, now try scientific */
2127 fmt
= unum_open(UNUM_SCIENTIFIC
, NULL
, -1, "en_US", NULL
, &status
);
2128 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status
);
2130 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==0);
2133 u_uastrcpy(str
, cstr
);
2136 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2137 ASSERT_TRUE(pos
==4);
2138 if(U_FAILURE(status
)) {
2139 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2140 } else if(expect
!=num
) {
2141 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2143 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2146 unum_setAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
, 1); /* no error code */
2147 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2149 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_PARSE_NO_EXPONENT
)==1);
2153 u_uastrcpy(str
, cstr
);
2156 num
= unum_parse(fmt
, str
, -1, &pos
, &status
);
2157 ASSERT_TRUE(pos
==4);
2158 if(U_FAILURE(status
)) {
2159 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__
, __LINE__
, u_errorName(status
), cstr
);
2160 } else if(expect
!=num
) {
2161 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__
, __LINE__
, num
, expect
, cstr
);
2163 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__
, __LINE__
, num
, cstr
);
2169 static void TestMaxInt(void) {
2170 UErrorCode status
= U_ZERO_ERROR
;
2171 UChar pattern_hash
[] = { 0x23, 0x00 }; /* "#" */
2172 UChar result1
[1024] = { 0 }, result2
[1024] = { 0 };
2174 UChar expect
[] = { 0x0039, 0x0037, 0 };
2175 UNumberFormat
*fmt
= unum_open(
2176 UNUM_PATTERN_DECIMAL
, /* style */
2177 &pattern_hash
[0], /* pattern */
2178 u_strlen(pattern_hash
), /* patternLength */
2182 if(U_FAILURE(status
) || fmt
== NULL
) {
2183 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__
, __LINE__
, "TestMaxInt", u_errorName(status
));
2187 unum_setAttribute(fmt
, UNUM_MAX_INTEGER_DIGITS
, 2);
2189 status
= U_ZERO_ERROR
;
2191 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2193 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2194 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2197 status
= U_ZERO_ERROR
;
2199 len2
= unum_formatDouble(fmt
, 1997.0, result2
, 1024, NULL
, &status
);
2201 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2202 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2207 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2208 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==0);
2210 unum_setAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
, 1);
2211 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2212 ASSERT_TRUE(unum_getAttribute(fmt
, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS
)==1);
2214 status
= U_ZERO_ERROR
;
2215 /* max int digits still '2' */
2216 len1
= unum_formatInt64(fmt
, 1997, result1
, 1024, NULL
, &status
);
2217 ASSERT_TRUE(status
==U_ILLEGAL_ARGUMENT_ERROR
);
2218 status
= U_ZERO_ERROR
;
2220 /* But, formatting 97->'97' works fine. */
2223 len1
= unum_formatInt64(fmt
, 97, result1
, 1024, NULL
, &status
);
2225 if(U_FAILURE(status
) || u_strcmp(expect
, result1
)) {
2226 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result1
), u_errorName(status
));
2229 status
= U_ZERO_ERROR
;
2231 len2
= unum_formatDouble(fmt
, 97.0, result2
, 1024, NULL
, &status
);
2233 if(U_FAILURE(status
) || u_strcmp(expect
, result2
)) {
2234 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect
), austrdup(result2
), u_errorName(status
));
2241 #endif /* #if !UCONFIG_NO_FORMATTING */