1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2013, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6 /********************************************************************************
7 *
8 * File CNUMTST.C
9 *
10 * Madhu Katragadda Creation
11 *
12 * Modification History:
13 *
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 *********************************************************************************
18 */
19
20 /* C API TEST FOR NUMBER FORMAT */
21
22 #include "unicode/utypes.h"
23
24 #if !UCONFIG_NO_FORMATTING
25
26 #include "unicode/uloc.h"
27 #include "unicode/umisc.h"
28 #include "unicode/unum.h"
29 #include "unicode/unumsys.h"
30 #include "unicode/ustring.h"
31
32 #include "cintltst.h"
33 #include "cnumtst.h"
34 #include "cmemory.h"
35 #include "cstring.h"
36 #include "putilimp.h"
37 #include <stdio.h>
38
39 #define LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
40
tagAssert(const char * f,int32_t l,const char * msg)41 static const char *tagAssert(const char *f, int32_t l, const char *msg) {
42 static char _fileline[1000];
43 sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg);
44 return _fileline;
45 }
46
47 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
48
49 void addNumForTest(TestNode** root);
50 static void TestTextAttributeCrash(void);
51 static void TestNBSPInPattern(void);
52 static void TestInt64Parse(void);
53 static void TestParseCurrency(void);
54 static void TestMaxInt(void);
55 static void TestNoExponent(void);
56 static void TestUFormattable(void);
57 static void TestUNumberingSystem(void);
58
59 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
60
addNumForTest(TestNode ** root)61 void addNumForTest(TestNode** root)
62 {
63 TESTCASE(TestNumberFormat);
64 TESTCASE(TestSpelloutNumberParse);
65 TESTCASE(TestSignificantDigits);
66 TESTCASE(TestSigDigRounding);
67 TESTCASE(TestNumberFormatPadding);
68 TESTCASE(TestInt64Format);
69 TESTCASE(TestNonExistentCurrency);
70 TESTCASE(TestCurrencyRegression);
71 TESTCASE(TestTextAttributeCrash);
72 TESTCASE(TestRBNFFormat);
73 TESTCASE(TestNBSPInPattern);
74 TESTCASE(TestInt64Parse);
75 TESTCASE(TestParseZero);
76 TESTCASE(TestParseCurrency);
77 TESTCASE(TestCloneWithRBNF);
78 TESTCASE(TestMaxInt);
79 TESTCASE(TestNoExponent);
80 TESTCASE(TestUFormattable);
81 TESTCASE(TestUNumberingSystem);
82 }
83
84 /* test Parse int 64 */
85
TestInt64Parse()86 static void TestInt64Parse()
87 {
88
89 UErrorCode st = U_ZERO_ERROR;
90 UErrorCode* status = &st;
91
92 const char* st1 = "009223372036854775808";
93 const int size = 21;
94 UChar text[21];
95
96
97 UNumberFormat* nf;
98
99 int64_t a;
100
101 u_charsToUChars(st1, text, size);
102 nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status);
103
104 if(U_FAILURE(*status))
105 {
106 log_data_err("Error in unum_open() %s \n", myErrorName(*status));
107 return;
108 }
109
110 log_verbose("About to test unum_parseInt64() with out of range number\n");
111
112 a = unum_parseInt64(nf, text, size, 0, status);
113 (void)a; /* Suppress set but not used warning. */
114
115
116 if(!U_FAILURE(*status))
117 {
118 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status));
119 }
120 else
121 {
122 log_verbose("unum_parseInt64() successful\n");
123 }
124
125 unum_close(nf);
126 return;
127 }
128
129 /* test Number Format API */
TestNumberFormat()130 static void TestNumberFormat()
131 {
132 UChar *result=NULL;
133 UChar temp1[512];
134 UChar temp2[512];
135
136 UChar temp[5];
137
138 UChar prefix[5];
139 UChar suffix[5];
140 UChar symbol[20];
141 int32_t resultlength;
142 int32_t resultlengthneeded;
143 int32_t parsepos;
144 double d1 = -1.0;
145 int32_t l1;
146 double d = -10456.37;
147 double a = 1234.56, a1 = 1235.0;
148 int32_t l = 100000000;
149 UFieldPosition pos1;
150 UFieldPosition pos2;
151 int32_t numlocales;
152 int32_t i;
153
154 UNumberFormatAttribute attr;
155 UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL;
156 int32_t newvalue;
157 UErrorCode status=U_ZERO_ERROR;
158 UNumberFormatStyle style= UNUM_DEFAULT;
159 UNumberFormat *pattern;
160 UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr,
161 *cur_frpattern, *myclone, *spellout_def;
162
163 /* Testing unum_open() with various Numberformat styles and locales*/
164 status = U_ZERO_ERROR;
165 log_verbose("Testing unum_open() with default style and locale\n");
166 def=unum_open(style, NULL,0,NULL, NULL,&status);
167
168 /* Might as well pack it in now if we can't even get a default NumberFormat... */
169 if(U_FAILURE(status))
170 {
171 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
172 return;
173 }
174
175 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
176 fr=unum_open(style,NULL,0, "fr_FR",NULL, &status);
177 if(U_FAILURE(status))
178 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status));
179
180 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
181 style=UNUM_CURRENCY;
182 /* Can't hardcode the result to assume the default locale is "en_US". */
183 cur_def=unum_open(style, NULL,0,"en_US", NULL, &status);
184 if(U_FAILURE(status))
185 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
186 myErrorName(status) );
187
188 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
189 cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status);
190 if(U_FAILURE(status))
191 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
192 myErrorName(status));
193
194 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
195 style=UNUM_PERCENT;
196 per_def=unum_open(style,NULL,0, NULL,NULL, &status);
197 if(U_FAILURE(status))
198 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status));
199
200 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
201 per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status);
202 if(U_FAILURE(status))
203 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status));
204
205 log_verbose("\nTesting unum_open(spellout, NULL, status)");
206 style=UNUM_SPELLOUT;
207 spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status);
208 if(U_FAILURE(status))
209 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status));
210
211 /* Testing unum_clone(..) */
212 log_verbose("\nTesting unum_clone(fmt, status)");
213 status = U_ZERO_ERROR;
214 myclone = unum_clone(def,&status);
215 if(U_FAILURE(status))
216 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status));
217 else
218 {
219 log_verbose("unum_clone() successful\n");
220 }
221
222 /*Testing unum_getAvailable() and unum_countAvailable()*/
223 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
224 numlocales=unum_countAvailable();
225 if(numlocales < 0)
226 log_err("error in countAvailable");
227 else{
228 log_verbose("unum_countAvialable() successful\n");
229 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales);
230 }
231 for(i=0;i<numlocales;i++)
232 {
233 log_verbose("%s\n", unum_getAvailable(i));
234 if (unum_getAvailable(i) == 0)
235 log_err("No locale for which number formatting patterns are applicable\n");
236 else
237 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i));
238 }
239
240
241 /*Testing unum_format() and unum_formatdouble()*/
242 u_uastrcpy(temp1, "$100,000,000.00");
243
244 log_verbose("\nTesting unum_format() \n");
245 resultlength=0;
246 pos1.field = UNUM_INTEGER_FIELD;
247 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
248 if(status==U_BUFFER_OVERFLOW_ERROR)
249 {
250 status=U_ZERO_ERROR;
251 resultlength=resultlengthneeded+1;
252 result=(UChar*)malloc(sizeof(UChar) * resultlength);
253 /* for (i = 0; i < 100000; i++) */
254 {
255 unum_format(cur_def, l, result, resultlength, &pos1, &status);
256 }
257 }
258
259 if(U_FAILURE(status))
260 {
261 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) );
262 }
263 if(u_strcmp(result, temp1)==0)
264 log_verbose("Pass: Number formatting using unum_format() successful\n");
265 else
266 log_err("Fail: Error in number Formatting using unum_format()\n");
267 if(pos1.beginIndex == 1 && pos1.endIndex == 12)
268 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
269 else
270 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
271 pos1.beginIndex, pos1.endIndex);
272
273 free(result);
274 result = 0;
275
276 log_verbose("\nTesting unum_formatDouble()\n");
277 u_uastrcpy(temp1, "-$10,456.37");
278 resultlength=0;
279 pos2.field = UNUM_FRACTION_FIELD;
280 resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status);
281 if(status==U_BUFFER_OVERFLOW_ERROR)
282 {
283 status=U_ZERO_ERROR;
284 resultlength=resultlengthneeded+1;
285 result=(UChar*)malloc(sizeof(UChar) * resultlength);
286 /* for (i = 0; i < 100000; i++) */
287 {
288 unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status);
289 }
290 }
291 if(U_FAILURE(status))
292 {
293 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
294 }
295 if(result && u_strcmp(result, temp1)==0)
296 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
297 else {
298 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
299 aescstrdup(result, -1), aescstrdup(temp1, -1));
300 }
301 if(pos2.beginIndex == 9 && pos2.endIndex == 11)
302 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
303 else
304 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
305 pos1.beginIndex, pos1.endIndex);
306
307
308 /* Testing unum_parse() and unum_parseDouble() */
309 log_verbose("\nTesting unum_parseDouble()\n");
310 /* for (i = 0; i < 100000; i++)*/
311 parsepos=0;
312 if (result != NULL) {
313 d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status);
314 } else {
315 log_err("result is NULL\n");
316 }
317 if(U_FAILURE(status)) {
318 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status));
319 }
320
321 if(d1!=d)
322 log_err("Fail: Error in parsing\n");
323 else
324 log_verbose("Pass: parsing successful\n");
325 if (result)
326 free(result);
327 result = 0;
328
329 status = U_ZERO_ERROR;
330 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
331 log_verbose("\nTesting unum_formatDoubleCurrency\n");
332 u_uastrcpy(temp1, "Y1,235");
333 temp1[0] = 0xA5; /* Yen sign */
334 u_uastrcpy(temp, "JPY");
335 resultlength=0;
336 pos2.field = UNUM_INTEGER_FIELD;
337 resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status);
338 if (status==U_BUFFER_OVERFLOW_ERROR) {
339 status=U_ZERO_ERROR;
340 resultlength=resultlengthneeded+1;
341 result=(UChar*)malloc(sizeof(UChar) * resultlength);
342 unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status);
343 }
344 if (U_FAILURE(status)) {
345 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
346 }
347 if (result && u_strcmp(result, temp1)==0) {
348 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
349 } else {
350 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
351 aescstrdup(result, -1), aescstrdup(temp1, -1));
352 }
353 if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
354 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
355 } else {
356 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
357 pos1.beginIndex, pos1.endIndex);
358 }
359
360 log_verbose("\nTesting unum_parseDoubleCurrency\n");
361 parsepos=0;
362 if (result == NULL) {
363 log_err("result is NULL\n");
364 }
365 else {
366 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
367 if (U_FAILURE(status)) {
368 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
369 }
370 /* Note: a==1234.56, but on parse expect a1=1235.0 */
371 if (d1!=a1) {
372 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1);
373 } else {
374 log_verbose("Pass: parsed currency amount successfully\n");
375 }
376 if (u_strcmp(temp2, temp)==0) {
377 log_verbose("Pass: parsed correct currency\n");
378 } else {
379 log_err("Fail: parsed incorrect currency\n");
380 }
381 }
382 status = U_ZERO_ERROR; /* reset */
383
384 free(result);
385 result = 0;
386
387
388 /* performance testing */
389 u_uastrcpy(temp1, "$462.12345");
390 resultlength=u_strlen(temp1);
391 /* for (i = 0; i < 100000; i++) */
392 {
393 parsepos=0;
394 d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status);
395 }
396 if(U_FAILURE(status))
397 {
398 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
399 }
400
401 /*
402 * Note: "for strict standard conformance all operations and constants are now supposed to be
403 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
404 */
405 a1 = 462.12345;
406
407 if(d1!=a1)
408 log_err("Fail: Error in parsing\n");
409 else
410 log_verbose("Pass: parsing successful\n");
411
412 free(result);
413
414 u_uastrcpy(temp1, "($10,456.3E1])");
415 parsepos=0;
416 d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status);
417 if(U_SUCCESS(status))
418 {
419 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status));
420 }
421
422
423 log_verbose("\nTesting unum_format()\n");
424 status=U_ZERO_ERROR;
425 resultlength=0;
426 parsepos=0;
427 resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status);
428 if(status==U_BUFFER_OVERFLOW_ERROR)
429 {
430 status=U_ZERO_ERROR;
431 resultlength=resultlengthneeded+1;
432 result=(UChar*)malloc(sizeof(UChar) * resultlength);
433 /* for (i = 0; i < 100000; i++)*/
434 {
435 unum_format(per_fr, l, result, resultlength, &pos1, &status);
436 }
437 }
438 if(U_FAILURE(status))
439 {
440 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
441 }
442
443
444 log_verbose("\nTesting unum_parse()\n");
445 /* for (i = 0; i < 100000; i++) */
446 {
447 parsepos=0;
448 l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status);
449 }
450 if(U_FAILURE(status))
451 {
452 log_err("parse failed. The error is : %s\n", myErrorName(status));
453 }
454
455 if(l1!=l)
456 log_err("Fail: Error in parsing\n");
457 else
458 log_verbose("Pass: parsing successful\n");
459
460 free(result);
461
462 /* create a number format using unum_openPattern(....)*/
463 log_verbose("\nTesting unum_openPattern()\n");
464 u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)");
465 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
466 if(U_FAILURE(status))
467 {
468 log_err("error in unum_openPattern(): %s\n", myErrorName(status) );;
469 }
470 else
471 log_verbose("Pass: unum_openPattern() works fine\n");
472
473 /*test for unum_toPattern()*/
474 log_verbose("\nTesting unum_toPattern()\n");
475 resultlength=0;
476 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
477 if(status==U_BUFFER_OVERFLOW_ERROR)
478 {
479 status=U_ZERO_ERROR;
480 resultlength=resultlengthneeded+1;
481 result=(UChar*)malloc(sizeof(UChar) * resultlength);
482 unum_toPattern(pattern, FALSE, result, resultlength, &status);
483 }
484 if(U_FAILURE(status))
485 {
486 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
487 }
488 else
489 {
490 if(u_strcmp(result, temp1)!=0)
491 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
492 else
493 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
494 free(result);
495 }
496
497 /*Testing unum_getSymbols() and unum_setSymbols()*/
498 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
499 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
500 resultlength=0;
501 resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status);
502 if(status==U_BUFFER_OVERFLOW_ERROR)
503 {
504 status=U_ZERO_ERROR;
505 resultlength=resultlengthneeded+1;
506 result=(UChar*)malloc(sizeof(UChar) * resultlength);
507 unum_toPattern(cur_def, FALSE, result, resultlength, &status);
508 }
509 if(U_FAILURE(status))
510 {
511 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
512 }
513
514 status=U_ZERO_ERROR;
515 cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status);
516 if(U_FAILURE(status))
517 {
518 log_err("error in unum_openPattern(): %s\n", myErrorName(status));
519 }
520
521 free(result);
522
523 /*getting the symbols of cur_def */
524 /*set the symbols of cur_frpattern to cur_def */
525 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
526 status=U_ZERO_ERROR;
527 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
528 unum_setSymbol(cur_frpattern, symType, temp1, -1, &status);
529 if(U_FAILURE(status))
530 {
531 log_err("Error in get/set symbols: %s\n", myErrorName(status));
532 }
533 }
534
535 /*format to check the result */
536 resultlength=0;
537 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
538 if(status==U_BUFFER_OVERFLOW_ERROR)
539 {
540 status=U_ZERO_ERROR;
541 resultlength=resultlengthneeded+1;
542 result=(UChar*)malloc(sizeof(UChar) * resultlength);
543 unum_format(cur_def, l, result, resultlength, &pos1, &status);
544 }
545 if(U_FAILURE(status))
546 {
547 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
548 }
549
550 if(U_FAILURE(status)){
551 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status));
552 }
553 unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL);
554
555 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
556 status=U_ZERO_ERROR;
557 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
558 unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status);
559 if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0)
560 {
561 log_err("Fail: error in getting symbols\n");
562 }
563 else
564 log_verbose("Pass: get and set symbols successful\n");
565 }
566
567 /*format and check with the previous result */
568
569 resultlength=0;
570 resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status);
571 if(status==U_BUFFER_OVERFLOW_ERROR)
572 {
573 status=U_ZERO_ERROR;
574 resultlength=resultlengthneeded+1;
575 unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status);
576 }
577 if(U_FAILURE(status))
578 {
579 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
580 }
581 /* TODO:
582 * This test fails because we have not called unum_applyPattern().
583 * Currently, such an applyPattern() does not exist on the C API, and
584 * we have jitterbug 411 for it.
585 * Since it is close to the 1.5 release, I (markus) am disabling this test just
586 * for this release (I added the test itself only last week).
587 * For the next release, we need to fix this.
588 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
589 */
590 if(u_strcmp(result, temp1) != 0) {
591 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1);
592 }
593
594
595 /*----------- */
596
597 free(result);
598
599 /* Testing unum_get/setSymbol() */
600 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
601 symbol[0] = (UChar)(0x41 + i);
602 symbol[1] = (UChar)(0x61 + i);
603 unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status);
604 if(U_FAILURE(status)) {
605 log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status));
606 return;
607 }
608 }
609 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
610 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status);
611 if(U_FAILURE(status)) {
612 log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status));
613 return;
614 }
615 if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) {
616 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i);
617 }
618 }
619 /*try getting from a bogus symbol*/
620 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status);
621 if(U_SUCCESS(status)){
622 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
623 }
624 if(U_FAILURE(status)){
625 if(status != U_ILLEGAL_ARGUMENT_ERROR){
626 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status));
627 }
628 }
629 status=U_ZERO_ERROR;
630
631 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
632 log_verbose("\nTesting getting and setting text attributes\n");
633 resultlength=5;
634 unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
635 if(U_FAILURE(status))
636 {
637 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
638 }
639 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
640 if(U_FAILURE(status))
641 {
642 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
643 }
644 unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status);
645 if(U_FAILURE(status))
646 {
647 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
648 }
649 if(u_strcmp(suffix,temp)!=0)
650 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
651 else
652 log_verbose("Pass: setting and getting suffix works fine\n");
653 /*set it back to normal */
654 u_uastrcpy(temp,"$");
655 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
656
657 /*checking some more text setter conditions */
658 u_uastrcpy(prefix, "+");
659 unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status);
660 if(U_FAILURE(status))
661 {
662 log_err("error in setting the text attributes : %s\n", myErrorName(status));
663 }
664 unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status);
665 if(U_FAILURE(status))
666 {
667 log_err("error in getting the text attributes : %s\n", myErrorName(status));
668 }
669
670 if(u_strcmp(prefix, temp)!=0)
671 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
672 else
673 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
674
675 u_uastrcpy(prefix, "+");
676 unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status);
677 if(U_FAILURE(status))
678 {
679 log_err("error in setting the text attributes : %s\n", myErrorName(status));
680 }
681 unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status);
682 if(U_FAILURE(status))
683 {
684 log_err("error in getting the text attributes : %s\n", myErrorName(status));
685 }
686 if(u_strcmp(prefix, temp)!=0)
687 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
688 else
689 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
690
691 u_uastrcpy(suffix, "+");
692 unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
693 if(U_FAILURE(status))
694 {
695 log_err("error in setting the text attributes: %s\n", myErrorName(status));
696 }
697
698 unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
699 if(U_FAILURE(status))
700 {
701 log_err("error in getting the text attributes : %s\n", myErrorName(status));
702 }
703 if(u_strcmp(suffix, temp)!=0)
704 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
705 else
706 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
707
708 u_uastrcpy(suffix, "++");
709 unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
710 if(U_FAILURE(status))
711 {
712 log_err("error in setting the text attributes: %s\n", myErrorName(status));
713 }
714
715 unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status);
716 if(U_FAILURE(status))
717 {
718 log_err("error in getting the text attributes : %s\n", myErrorName(status));
719 }
720 if(u_strcmp(suffix, temp)!=0)
721 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
722 else
723 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
724
725 /*Testing unum_getAttribute and unum_setAttribute() */
726 log_verbose("\nTesting get and set Attributes\n");
727 attr=UNUM_GROUPING_SIZE;
728 newvalue=unum_getAttribute(def, attr);
729 newvalue=2;
730 unum_setAttribute(def, attr, newvalue);
731 if(unum_getAttribute(def,attr)!=2)
732 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
733 else
734 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
735
736 attr=UNUM_MULTIPLIER;
737 newvalue=unum_getAttribute(def, attr);
738 newvalue=8;
739 unum_setAttribute(def, attr, newvalue);
740 if(unum_getAttribute(def,attr) != 8)
741 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
742 else
743 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
744
745 attr=UNUM_SECONDARY_GROUPING_SIZE;
746 newvalue=unum_getAttribute(def, attr);
747 newvalue=2;
748 unum_setAttribute(def, attr, newvalue);
749 if(unum_getAttribute(def,attr) != 2)
750 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
751 else
752 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
753
754 /*testing set and get Attributes extensively */
755 log_verbose("\nTesting get and set attributes extensively\n");
756 for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) )
757 {
758 newvalue=unum_getAttribute(fr, attr);
759 unum_setAttribute(def, attr, newvalue);
760 if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr))
761 log_err("error in setting and getting attributes\n");
762 else
763 log_verbose("Pass: attributes set and retrieved successfully\n");
764 }
765
766 /*testing spellout format to make sure we can use it successfully.*/
767 log_verbose("\nTesting spellout format\n");
768 if (spellout_def)
769 {
770 static const int32_t values[] = { 0, -5, 105, 1005, 105050 };
771 for (i = 0; i < LENGTH(values); ++i) {
772 UChar buffer[128];
773 int32_t len;
774 int32_t value = values[i];
775 status = U_ZERO_ERROR;
776 len = unum_format(spellout_def, value, buffer, LENGTH(buffer), NULL, &status);
777 if(U_FAILURE(status)) {
778 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
779 } else {
780 int32_t pp = 0;
781 int32_t parseResult;
782 /*ustrToAstr(buffer, len, logbuf, LENGTH(logbuf));*/
783 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
784
785 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status);
786 if (U_FAILURE(status)) {
787 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
788 } else if (parseResult != value) {
789 log_err("unum_format result %d != value %d\n", parseResult, value);
790 }
791 }
792 }
793 }
794 else {
795 log_err("Spellout format is unavailable\n");
796 }
797
798 { /* Test for ticket #7079 */
799 UNumberFormat* dec_en;
800 UChar groupingSep[] = { 0 };
801 UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
802 double parseResult = 0.0;
803
804 status=U_ZERO_ERROR;
805 dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
806 unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0);
807 unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status);
808 parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status);
809 /* Without the fix in #7079, the above call will hang */
810 if ( U_FAILURE(status) || parseResult != 12.0 ) {
811 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
812 myErrorName(status), parseResult);
813 } else {
814 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
815 }
816 unum_close(dec_en);
817 }
818
819 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
820 to verify that it is taking the pure decimal path. */
821 UNumberFormat *fmt;
822 const char *bdpattern = "#,##0.#########";
823 const char *numInitial = "12345678900987654321.1234567896";
824 const char *numFormatted = "12,345,678,900,987,654,321.12345679";
825 const char *parseExpected = "12345678900987654321.12345679";
826 int32_t resultSize = 0;
827 int32_t parsePos = 0; /* Output parameter for Parse operations. */
828 #define DESTCAPACITY 100
829 UChar dest[DESTCAPACITY];
830 char desta[DESTCAPACITY];
831 UFieldPosition fieldPos = {0};
832
833 /* Format */
834
835 status = U_ZERO_ERROR;
836 u_uastrcpy(dest, bdpattern);
837 fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status);
838 if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
839
840 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status);
841 if (U_FAILURE(status)) {
842 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
843 }
844 u_austrncpy(desta, dest, DESTCAPACITY);
845 if (strcmp(numFormatted, desta) != 0) {
846 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
847 __FILE__, __LINE__, numFormatted, desta);
848 }
849 if (strlen(numFormatted) != resultSize) {
850 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
851 __FILE__, __LINE__, strlen(numFormatted), resultSize);
852 }
853
854 /* Format with a FieldPosition parameter */
855
856 fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
857 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status);
858 if (U_FAILURE(status)) {
859 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
860 }
861 u_austrncpy(desta, dest, DESTCAPACITY);
862 if (strcmp(numFormatted, desta) != 0) {
863 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
864 __FILE__, __LINE__, numFormatted, desta);
865 }
866 if (fieldPos.beginIndex != 26) { /* index of "." in formatted number */
867 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
868 __FILE__, __LINE__, 0, fieldPos.beginIndex);
869 }
870 if (fieldPos.endIndex != 27) {
871 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
872 __FILE__, __LINE__, 0, fieldPos.endIndex);
873 }
874
875 /* Parse */
876
877 status = U_ZERO_ERROR;
878 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
879 resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status);
880 if (U_FAILURE(status)) {
881 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
882 }
883 if (strcmp(parseExpected, desta) != 0) {
884 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
885 __FILE__, __LINE__, parseExpected, desta);
886 }
887 if (strlen(parseExpected) != resultSize) {
888 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
889 __FILE__, __LINE__, strlen(parseExpected), resultSize);
890 }
891
892 /* Parse with a parsePos parameter */
893
894 status = U_ZERO_ERROR;
895 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
896 parsePos = 3; /* 12,345,678,900,987,654,321.12345679 */
897 /* start parsing at the the third char */
898 resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status);
899 if (U_FAILURE(status)) {
900 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
901 }
902 if (strcmp(parseExpected+2, desta) != 0) { /* "345678900987654321.12345679" */
903 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
904 __FILE__, __LINE__, parseExpected+2, desta);
905 }
906 if (strlen(numFormatted) != parsePos) {
907 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
908 __FILE__, __LINE__, strlen(parseExpected), parsePos);
909 }
910
911 unum_close(fmt);
912 }
913
914 status = U_ZERO_ERROR;
915 /* Test invalid symbol argument */
916 {
917 int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1;
918 int32_t badsymbolSmall = -1;
919 UChar value[10];
920 int32_t valueLength = 10;
921 UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
922 if (U_FAILURE(status)) {
923 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
924 } else {
925 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status);
926 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
927
928 status = U_ZERO_ERROR;
929 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status);
930 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
931
932 status = U_ZERO_ERROR;
933 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status);
934 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
935
936 status = U_ZERO_ERROR;
937 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status);
938 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
939
940 unum_close(fmt);
941 }
942 }
943
944
945 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
946 unum_close(def);
947 unum_close(fr);
948 unum_close(cur_def);
949 unum_close(cur_fr);
950 unum_close(per_def);
951 unum_close(per_fr);
952 unum_close(spellout_def);
953 unum_close(pattern);
954 unum_close(cur_frpattern);
955 unum_close(myclone);
956
957 }
958
TestParseZero(void)959 static void TestParseZero(void)
960 {
961 UErrorCode errorCode = U_ZERO_ERROR;
962 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */
963 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
964 double dbl;
965
966 #if 0
967 UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode);
968 #else
969 UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode);
970 #endif
971
972 dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode );
973 if (U_FAILURE(errorCode)) {
974 log_data_err("Result - %s\n", u_errorName(errorCode));
975 } else {
976 log_verbose("Double: %f\n", dbl);
977 }
978 unum_close(unum);
979 }
980
981 static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
982 static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */
983 static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
984 static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
985 static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */
986 static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
987 static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
988 static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
989 static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
990 static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
991 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 */
992 static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
993 static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
994
995 typedef struct {
996 const char * locale;
997 const char * descrip;
998 const UChar * currStr;
999 const UChar * plurStr;
1000 UErrorCode parsDoubExpectErr;
1001 int32_t parsDoubExpectPos;
1002 double parsDoubExpectVal;
1003 UErrorCode parsCurrExpectErr;
1004 int32_t parsCurrExpectPos;
1005 double parsCurrExpectVal;
1006 const char * parsCurrExpectCurr;
1007 } ParseCurrencyItem;
1008
1009 static const ParseCurrencyItem parseCurrencyItems[] = {
1010 { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" },
1011 { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" },
1012 { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1013 { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1014 { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1015 { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1016 { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1017
1018 { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1019 { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1020 { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1021 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, "" },
1022 { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1023 { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1024 { "en_GB", "dollars4", dollars4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 4.0, "USD" },
1025
1026 { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" },
1027 { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" },
1028 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1029 { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1030 { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1031
1032 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL }
1033 };
1034
TestParseCurrency()1035 static void TestParseCurrency()
1036 {
1037 const ParseCurrencyItem * itemPtr;
1038 for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) {
1039 UNumberFormat* unum;
1040 UErrorCode status;
1041 double parseVal;
1042 int32_t parsePos;
1043 UChar parseCurr[4];
1044 char parseCurrB[4];
1045
1046 status = U_ZERO_ERROR;
1047 unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
1048 if (U_SUCCESS(status)) {
1049 status = U_ZERO_ERROR;
1050 parsePos = 0;
1051 parseVal = unum_parseDouble(unum, itemPtr->currStr, -1, &parsePos, &status);
1052 if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
1053 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1054 itemPtr->locale, itemPtr->descrip,
1055 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
1056 u_errorName(status), parsePos, parseVal );
1057 }
1058 status = U_ZERO_ERROR;
1059 parsePos = 0;
1060 parseCurr[0] = 0;
1061 parseVal = unum_parseDoubleCurrency(unum, itemPtr->currStr, -1, &parsePos, parseCurr, &status);
1062 u_austrncpy(parseCurrB, parseCurr, 4);
1063 if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal ||
1064 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1065 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1066 itemPtr->locale, itemPtr->descrip,
1067 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1068 u_errorName(status), parsePos, parseVal, parseCurrB );
1069 }
1070 unum_close(unum);
1071 } else {
1072 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1073 }
1074
1075 #if 0
1076 /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */
1077 if (itemPtr->plurStr != NULL) {
1078 status = U_ZERO_ERROR;
1079 unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status);
1080 if (U_SUCCESS(status)) {
1081 status = U_ZERO_ERROR;
1082 parsePos = 0;
1083 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
1084 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
1085 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
1086 itemPtr->locale, itemPtr->descrip,
1087 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
1088 u_errorName(status), parseVal );
1089 }
1090 status = U_ZERO_ERROR;
1091 parsePos = 0;
1092 parseCurr[0] = 0;
1093 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status);
1094 u_austrncpy(parseCurrB, parseCurr, 4);
1095 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal ||
1096 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1097 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1098 itemPtr->locale, itemPtr->descrip,
1099 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1100 u_errorName(status), parseVal, parseCurrB );
1101 }
1102 unum_close(unum);
1103 } else {
1104 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1105 }
1106 }
1107 #endif
1108 }
1109 }
1110
1111 typedef struct {
1112 const char * testname;
1113 const char * locale;
1114 const UChar * source;
1115 int32_t startPos;
1116 int32_t value;
1117 int32_t endPos;
1118 UErrorCode status;
1119 } SpelloutParseTest;
1120
1121 static const UChar ustr_en0[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1122 static const UChar ustr_123[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1123 static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1124 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1125 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1126 static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1127 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
1128 static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1129
1130 static const SpelloutParseTest spelloutParseTests[] = {
1131 /* name loc src start val end status */
1132 { "en0", "en", ustr_en0, 0, 0, 4, U_ZERO_ERROR },
1133 { "en0", "en", ustr_en0, 2, 0, 2, U_PARSE_ERROR },
1134 { "en0", "ja", ustr_en0, 0, 0, 0, U_PARSE_ERROR },
1135 { "123", "en", ustr_123, 0, 123, 3, U_ZERO_ERROR },
1136 { "en123", "en", ustr_en123, 0, 123, 24, U_ZERO_ERROR },
1137 { "en123", "en", ustr_en123, 12, 23, 24, U_ZERO_ERROR },
1138 { "en123", "fr", ustr_en123, 16, 0, 16, U_PARSE_ERROR },
1139 { "fr123", "fr", ustr_fr123, 0, 123, 16, U_ZERO_ERROR },
1140 { "fr123", "fr", ustr_fr123, 5, 23, 16, U_ZERO_ERROR },
1141 { "fr123", "en", ustr_fr123, 0, 0, 0, U_PARSE_ERROR },
1142 { "ja123", "ja", ustr_ja123, 0, 123, 4, U_ZERO_ERROR },
1143 { "ja123", "ja", ustr_ja123, 1, 23, 4, U_ZERO_ERROR },
1144 { "ja123", "fr", ustr_ja123, 0, 0, 0, U_PARSE_ERROR },
1145 { NULL, NULL, NULL, 0, 0, 0, 0 } /* terminator */
1146 };
1147
TestSpelloutNumberParse()1148 static void TestSpelloutNumberParse()
1149 {
1150 const SpelloutParseTest * testPtr;
1151 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
1152 UErrorCode status = U_ZERO_ERROR;
1153 int32_t value, position = testPtr->startPos;
1154 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
1155 if (U_FAILURE(status)) {
1156 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1157 continue;
1158 }
1159 value = unum_parse(nf, testPtr->source, -1, &position, &status);
1160 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1161 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1162 testPtr->locale, testPtr->testname, testPtr->startPos,
1163 testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1164 value, position, myErrorName(status) );
1165 }
1166 unum_close(nf);
1167 }
1168 }
1169
TestSignificantDigits()1170 static void TestSignificantDigits()
1171 {
1172 UChar temp[128];
1173 int32_t resultlengthneeded;
1174 int32_t resultlength;
1175 UErrorCode status = U_ZERO_ERROR;
1176 UChar *result = NULL;
1177 UNumberFormat* fmt;
1178 double d = 123456.789;
1179
1180 u_uastrcpy(temp, "###0.0#");
1181 fmt=unum_open(UNUM_IGNORE, temp, -1, NULL, NULL,&status);
1182 if (U_FAILURE(status)) {
1183 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1184 return;
1185 }
1186 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1187 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6);
1188
1189 u_uastrcpy(temp, "123457");
1190 resultlength=0;
1191 resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status);
1192 if(status==U_BUFFER_OVERFLOW_ERROR)
1193 {
1194 status=U_ZERO_ERROR;
1195 resultlength=resultlengthneeded+1;
1196 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1197 unum_formatDouble(fmt, d, result, resultlength, NULL, &status);
1198 }
1199 if(U_FAILURE(status))
1200 {
1201 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1202 return;
1203 }
1204 if(u_strcmp(result, temp)==0)
1205 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1206 else
1207 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1208 free(result);
1209 unum_close(fmt);
1210 }
1211
TestSigDigRounding()1212 static void TestSigDigRounding()
1213 {
1214 UErrorCode status = U_ZERO_ERROR;
1215 UChar expected[128];
1216 UChar result[128];
1217 char temp1[128];
1218 char temp2[128];
1219 UNumberFormat* fmt;
1220 double d = 123.4;
1221
1222 fmt=unum_open(UNUM_DECIMAL, NULL, 0, NULL /* "en_US"*/, NULL, &status);
1223 if (U_FAILURE(status)) {
1224 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1225 return;
1226 }
1227 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE);
1228 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1229 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2);
1230 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1231
1232 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP);
1233 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0);
1234
1235 (void)unum_formatDouble(fmt, d, result, sizeof(result) / sizeof(result[0]), NULL, &status);
1236 if(U_FAILURE(status))
1237 {
1238 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1239 return;
1240 }
1241
1242 u_uastrcpy(expected, "140");
1243 if(u_strcmp(result, expected)!=0)
1244 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) );
1245
1246 unum_close(fmt);
1247 }
1248
TestNumberFormatPadding()1249 static void TestNumberFormatPadding()
1250 {
1251 UChar *result=NULL;
1252 UChar temp1[512];
1253
1254 UErrorCode status=U_ZERO_ERROR;
1255 int32_t resultlength;
1256 int32_t resultlengthneeded;
1257 UNumberFormat *pattern;
1258 double d1;
1259 double d = -10456.37;
1260 UFieldPosition pos1;
1261 int32_t parsepos;
1262
1263 /* create a number format using unum_openPattern(....)*/
1264 log_verbose("\nTesting unum_openPattern() with padding\n");
1265 u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)");
1266 status=U_ZERO_ERROR;
1267 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
1268 if(U_SUCCESS(status))
1269 {
1270 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
1271 }
1272 else
1273 {
1274 unum_close(pattern);
1275 }
1276
1277 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1278 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
1279 status=U_ZERO_ERROR;
1280 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
1281 if(U_FAILURE(status))
1282 {
1283 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
1284 }
1285 else {
1286 log_verbose("Pass: padding unum_openPattern() works fine\n");
1287
1288 /*test for unum_toPattern()*/
1289 log_verbose("\nTesting padding unum_toPattern()\n");
1290 resultlength=0;
1291 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
1292 if(status==U_BUFFER_OVERFLOW_ERROR)
1293 {
1294 status=U_ZERO_ERROR;
1295 resultlength=resultlengthneeded+1;
1296 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1297 unum_toPattern(pattern, FALSE, result, resultlength, &status);
1298 }
1299 if(U_FAILURE(status))
1300 {
1301 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status));
1302 }
1303 else
1304 {
1305 if(u_strcmp(result, temp1)!=0)
1306 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
1307 else
1308 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1309 free(result);
1310 }
1311 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1312 u_uastrcpy(temp1, "xxxxx(10,456.37)");
1313 resultlength=0;
1314 pos1.field = UNUM_FRACTION_FIELD;
1315 resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status);
1316 if(status==U_BUFFER_OVERFLOW_ERROR)
1317 {
1318 status=U_ZERO_ERROR;
1319 resultlength=resultlengthneeded+1;
1320 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1321 unum_formatDouble(pattern, d, result, resultlength, NULL, &status);
1322 }
1323 if(U_FAILURE(status))
1324 {
1325 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status));
1326 }
1327 else
1328 {
1329 if(u_strcmp(result, temp1)==0)
1330 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1331 else
1332 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1333 if(pos1.beginIndex == 13 && pos1.endIndex == 15)
1334 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1335 else
1336 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1337 pos1.beginIndex, pos1.endIndex);
1338
1339
1340 /* Testing unum_parse() and unum_parseDouble() */
1341 log_verbose("\nTesting padding unum_parseDouble()\n");
1342 parsepos=0;
1343 d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status);
1344 if(U_FAILURE(status))
1345 {
1346 log_err("padding parse failed. The error is : %s\n", myErrorName(status));
1347 }
1348
1349 if(d1!=d)
1350 log_err("Fail: Error in padding parsing\n");
1351 else
1352 log_verbose("Pass: padding parsing successful\n");
1353 free(result);
1354 }
1355 }
1356
1357 unum_close(pattern);
1358 }
1359
1360 static UBool
withinErr(double a,double b,double err)1361 withinErr(double a, double b, double err) {
1362 return uprv_fabs(a - b) < uprv_fabs(a * err);
1363 }
1364
TestInt64Format()1365 static void TestInt64Format() {
1366 UChar temp1[512];
1367 UChar result[512];
1368 UNumberFormat *fmt;
1369 UErrorCode status = U_ZERO_ERROR;
1370 const double doubleInt64Max = (double)U_INT64_MAX;
1371 const double doubleInt64Min = (double)U_INT64_MIN;
1372 const double doubleBig = 10.0 * (double)U_INT64_MAX;
1373 int32_t val32;
1374 int64_t val64;
1375 double valDouble;
1376 int32_t parsepos;
1377
1378 /* create a number format using unum_openPattern(....) */
1379 log_verbose("\nTesting Int64Format\n");
1380 u_uastrcpy(temp1, "#.#E0");
1381 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), NULL, NULL, &status);
1382 if(U_FAILURE(status)) {
1383 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
1384 } else {
1385 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20);
1386 unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status);
1387 if (U_FAILURE(status)) {
1388 log_err("error in unum_format(): %s\n", myErrorName(status));
1389 } else {
1390 log_verbose("format int64max: '%s'\n", result);
1391 parsepos = 0;
1392 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1393 if (status != U_INVALID_FORMAT_ERROR) {
1394 log_err("parse didn't report error: %s\n", myErrorName(status));
1395 } else if (val32 != INT32_MAX) {
1396 log_err("parse didn't pin return value, got: %d\n", val32);
1397 }
1398
1399 status = U_ZERO_ERROR;
1400 parsepos = 0;
1401 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1402 if (U_FAILURE(status)) {
1403 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1404 } else if (val64 != U_INT64_MAX) {
1405 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1406 }
1407
1408 status = U_ZERO_ERROR;
1409 parsepos = 0;
1410 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1411 if (U_FAILURE(status)) {
1412 log_err("parseDouble returned error: %s\n", myErrorName(status));
1413 } else if (valDouble != doubleInt64Max) {
1414 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1415 }
1416 }
1417
1418 unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status);
1419 if (U_FAILURE(status)) {
1420 log_err("error in unum_format(): %s\n", myErrorName(status));
1421 } else {
1422 log_verbose("format int64min: '%s'\n", result);
1423 parsepos = 0;
1424 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1425 if (status != U_INVALID_FORMAT_ERROR) {
1426 log_err("parse didn't report error: %s\n", myErrorName(status));
1427 } else if (val32 != INT32_MIN) {
1428 log_err("parse didn't pin return value, got: %d\n", val32);
1429 }
1430
1431 status = U_ZERO_ERROR;
1432 parsepos = 0;
1433 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1434 if (U_FAILURE(status)) {
1435 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1436 } else if (val64 != U_INT64_MIN) {
1437 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1438 }
1439
1440 status = U_ZERO_ERROR;
1441 parsepos = 0;
1442 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1443 if (U_FAILURE(status)) {
1444 log_err("parseDouble returned error: %s\n", myErrorName(status));
1445 } else if (valDouble != doubleInt64Min) {
1446 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1447 }
1448 }
1449
1450 unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status);
1451 if (U_FAILURE(status)) {
1452 log_err("error in unum_format(): %s\n", myErrorName(status));
1453 } else {
1454 log_verbose("format doubleBig: '%s'\n", result);
1455 parsepos = 0;
1456 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1457 if (status != U_INVALID_FORMAT_ERROR) {
1458 log_err("parse didn't report error: %s\n", myErrorName(status));
1459 } else if (val32 != INT32_MAX) {
1460 log_err("parse didn't pin return value, got: %d\n", val32);
1461 }
1462
1463 status = U_ZERO_ERROR;
1464 parsepos = 0;
1465 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1466 if (status != U_INVALID_FORMAT_ERROR) {
1467 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status));
1468 } else if (val64 != U_INT64_MAX) {
1469 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1470 }
1471
1472 status = U_ZERO_ERROR;
1473 parsepos = 0;
1474 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1475 if (U_FAILURE(status)) {
1476 log_err("parseDouble returned error: %s\n", myErrorName(status));
1477 } else if (!withinErr(valDouble, doubleBig, 1e-15)) {
1478 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1479 }
1480 }
1481
1482 u_uastrcpy(result, "5.06e-27");
1483 parsepos = 0;
1484 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1485 if (U_FAILURE(status)) {
1486 log_err("parseDouble() returned error: %s\n", myErrorName(status));
1487 } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) {
1488 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble);
1489 }
1490 }
1491 unum_close(fmt);
1492 }
1493
1494
test_fmt(UNumberFormat * fmt,UBool isDecimal)1495 static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
1496 char temp[512];
1497 UChar buffer[512];
1498 int32_t BUFSIZE = sizeof(buffer)/sizeof(buffer[0]);
1499 double vals[] = {
1500 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1501 };
1502 int i;
1503
1504 for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) {
1505 UErrorCode status = U_ZERO_ERROR;
1506 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1507 if (U_FAILURE(status)) {
1508 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1509 } else {
1510 u_austrcpy(temp, buffer);
1511 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1512 }
1513 }
1514
1515 /* check APIs now */
1516 {
1517 UErrorCode status = U_ZERO_ERROR;
1518 UParseError perr;
1519 u_uastrcpy(buffer, "#,##0.0#");
1520 unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status);
1521 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1522 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status));
1523 }
1524 }
1525
1526 {
1527 int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1528 log_verbose("lenient: 0x%x\n", isLenient);
1529 if (isLenient != FALSE) {
1530 log_err("didn't expect lenient value: %d\n", isLenient);
1531 }
1532
1533 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE);
1534 isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1535 if (isLenient != TRUE) {
1536 log_err("didn't expect lenient value after set: %d\n", isLenient);
1537 }
1538 }
1539
1540 {
1541 double val2;
1542 double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE);
1543 if (val != -1) {
1544 log_err("didn't expect double attribute\n");
1545 }
1546 val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1547 if ((val == -1) == isDecimal) {
1548 log_err("didn't expect -1 rounding increment\n");
1549 }
1550 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5);
1551 val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1552 if (isDecimal && (val2 - val != .5)) {
1553 log_err("set rounding increment had no effect on decimal format");
1554 }
1555 }
1556
1557 {
1558 UErrorCode status = U_ZERO_ERROR;
1559 int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1560 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1561 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status));
1562 }
1563 if (U_SUCCESS(status)) {
1564 u_austrcpy(temp, buffer);
1565 log_verbose("default ruleset: '%s'\n", temp);
1566 }
1567
1568 status = U_ZERO_ERROR;
1569 len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status);
1570 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1571 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status));
1572 }
1573 if (U_SUCCESS(status)) {
1574 u_austrcpy(temp, buffer);
1575 log_verbose("public rulesets: '%s'\n", temp);
1576
1577 /* set the default ruleset to the first one found, and retry */
1578
1579 if (len > 0) {
1580 for (i = 0; i < len && temp[i] != ';'; ++i){};
1581 if (i < len) {
1582 buffer[i] = 0;
1583 unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status);
1584 if (U_FAILURE(status)) {
1585 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status));
1586 } else {
1587 int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1588 if (U_FAILURE(status)) {
1589 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status));
1590 } else if (len2 != i) {
1591 u_austrcpy(temp, buffer);
1592 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp);
1593 } else {
1594 for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) {
1595 status = U_ZERO_ERROR;
1596 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1597 if (U_FAILURE(status)) {
1598 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1599 } else {
1600 u_austrcpy(temp, buffer);
1601 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1602 }
1603 }
1604 }
1605 }
1606 }
1607 }
1608 }
1609 }
1610
1611 {
1612 UErrorCode status = U_ZERO_ERROR;
1613 unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status);
1614 if (U_SUCCESS(status)) {
1615 u_austrcpy(temp, buffer);
1616 log_verbose("pattern: '%s'\n", temp);
1617 } else if (status != U_BUFFER_OVERFLOW_ERROR) {
1618 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status));
1619 } else {
1620 log_verbose("pattern too long to display\n");
1621 }
1622 }
1623
1624 {
1625 UErrorCode status = U_ZERO_ERROR;
1626 int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status);
1627 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1628 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status));
1629 }
1630
1631 unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status);
1632 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1633 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status));
1634 }
1635 }
1636 }
1637
TestNonExistentCurrency()1638 static void TestNonExistentCurrency() {
1639 UNumberFormat *format;
1640 UErrorCode status = U_ZERO_ERROR;
1641 UChar currencySymbol[8];
1642 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
1643
1644 /* Get a non-existent currency and make sure it returns the correct currency code. */
1645 format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status);
1646 if (format == NULL || U_FAILURE(status)) {
1647 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status));
1648 }
1649 else {
1650 unum_getSymbol(format,
1651 UNUM_CURRENCY_SYMBOL,
1652 currencySymbol,
1653 sizeof(currencySymbol)/sizeof(currencySymbol[0]),
1654 &status);
1655 if (u_strcmp(currencySymbol, QQQ) != 0) {
1656 log_err("unum_open set the currency to QQQ\n");
1657 }
1658 }
1659 unum_close(format);
1660 }
1661
TestRBNFFormat()1662 static void TestRBNFFormat() {
1663 UErrorCode status;
1664 UParseError perr;
1665 UChar pat[1024];
1666 UChar tempUChars[512];
1667 UNumberFormat *formats[5];
1668 int COUNT = sizeof(formats)/sizeof(formats[0]);
1669 int i;
1670
1671 for (i = 0; i < COUNT; ++i) {
1672 formats[i] = 0;
1673 }
1674
1675 /* instantiation */
1676 status = U_ZERO_ERROR;
1677 u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)");
1678 formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status);
1679 if (U_FAILURE(status)) {
1680 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
1681 return;
1682 }
1683
1684 status = U_ZERO_ERROR;
1685 formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status);
1686 if (U_FAILURE(status)) {
1687 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1688 return;
1689 }
1690
1691 status = U_ZERO_ERROR;
1692 formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status);
1693 if (U_FAILURE(status)) {
1694 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
1695 return;
1696 }
1697
1698 status = U_ZERO_ERROR;
1699 formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status);
1700 if (U_FAILURE(status)) {
1701 log_err_status(status, "unable to open duration %s\n", u_errorName(status));
1702 return;
1703 }
1704
1705 status = U_ZERO_ERROR;
1706 u_uastrcpy(pat,
1707 "%standard:\n"
1708 "-x: minus >>;\n"
1709 "x.x: << point >>;\n"
1710 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1711 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1712 "seventeen; eighteen; nineteen;\n"
1713 "20: twenty[->>];\n"
1714 "30: thirty[->>];\n"
1715 "40: forty[->>];\n"
1716 "50: fifty[->>];\n"
1717 "60: sixty[->>];\n"
1718 "70: seventy[->>];\n"
1719 "80: eighty[->>];\n"
1720 "90: ninety[->>];\n"
1721 "100: =#,##0=;\n");
1722 u_uastrcpy(tempUChars,
1723 "%simple:\n"
1724 "=%standard=;\n"
1725 "20: twenty[ and change];\n"
1726 "30: thirty[ and change];\n"
1727 "40: forty[ and change];\n"
1728 "50: fifty[ and change];\n"
1729 "60: sixty[ and change];\n"
1730 "70: seventy[ and change];\n"
1731 "80: eighty[ and change];\n"
1732 "90: ninety[ and change];\n"
1733 "100: =#,##0=;\n"
1734 "%bogus:\n"
1735 "0.x: tiny;\n"
1736 "x.x: << point something;\n"
1737 "=%standard=;\n"
1738 "20: some reasonable number;\n"
1739 "100: some substantial number;\n"
1740 "100,000,000: some huge number;\n");
1741 /* This is to get around some compiler warnings about char * string length. */
1742 u_strcat(pat, tempUChars);
1743 formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status);
1744 if (U_FAILURE(status)) {
1745 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
1746 }
1747 if (U_FAILURE(status)) {
1748 log_err_status(status, "Something failed with %s\n", u_errorName(status));
1749 return;
1750 }
1751
1752 for (i = 0; i < COUNT; ++i) {
1753 log_verbose("\n\ntesting format %d\n", i);
1754 test_fmt(formats[i], (UBool)(i == 0));
1755 }
1756
1757 #define FORMAT_BUF_CAPACITY 64
1758 {
1759 UChar fmtbuf[FORMAT_BUF_CAPACITY];
1760 int32_t len;
1761 double nanvalue = uprv_getNaN();
1762 status = U_ZERO_ERROR;
1763 len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1764 if (U_FAILURE(status)) {
1765 log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status));
1766 } else {
1767 UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1768 if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) {
1769 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1770 }
1771 }
1772 }
1773
1774 for (i = 0; i < COUNT; ++i) {
1775 unum_close(formats[i]);
1776 }
1777 }
1778
TestCurrencyRegression(void)1779 static void TestCurrencyRegression(void) {
1780 /*
1781 I've found a case where unum_parseDoubleCurrency is not doing what I
1782 expect. The value I pass in is $1234567890q123460000.00 and this
1783 returns with a status of zero error & a parse pos of 22 (I would
1784 expect a parse error at position 11).
1785
1786 I stepped into DecimalFormat::subparse() and it looks like it parses
1787 the first 10 digits and then stops parsing at the q but doesn't set an
1788 error. Then later in DecimalFormat::parse() the value gets crammed
1789 into a long (which greatly truncates the value).
1790
1791 This is very problematic for me 'cause I try to remove chars that are
1792 invalid but this allows my users to enter bad chars and truncates
1793 their data!
1794 */
1795
1796 UChar buf[1024];
1797 UChar currency[8];
1798 char acurrency[16];
1799 double d;
1800 UNumberFormat *cur;
1801 int32_t pos;
1802 UErrorCode status = U_ZERO_ERROR;
1803 const int32_t expected = 11;
1804
1805 currency[0]=0;
1806 u_uastrcpy(buf, "$1234567890q643210000.00");
1807 cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status);
1808
1809 if(U_FAILURE(status)) {
1810 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
1811 return;
1812 }
1813
1814 status = U_ZERO_ERROR; /* so we can test it later. */
1815 pos = 0;
1816
1817 d = unum_parseDoubleCurrency(cur,
1818 buf,
1819 -1,
1820 &pos, /* 0 = start */
1821 currency,
1822 &status);
1823
1824 u_austrcpy(acurrency, currency);
1825
1826 if(U_FAILURE(status) || (pos != expected)) {
1827 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1828 expected, d, u_errorName(status), pos, acurrency);
1829 } else {
1830 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency);
1831 }
1832
1833 unum_close(cur);
1834 }
1835
TestTextAttributeCrash(void)1836 static void TestTextAttributeCrash(void) {
1837 UChar ubuffer[64] = {0x0049,0x004E,0x0052,0};
1838 static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1839 static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1840 int32_t used;
1841 UErrorCode status = U_ZERO_ERROR;
1842 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
1843 if (U_FAILURE(status)) {
1844 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
1845 return;
1846 }
1847 unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status);
1848 /*
1849 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1850 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1851 */
1852 used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status);
1853 unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status);
1854 if (U_FAILURE(status)) {
1855 log_err("FAILED 2\n"); exit(1);
1856 }
1857 log_verbose("attempting to format...\n");
1858 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
1859 if (U_FAILURE(status) || 64 < used) {
1860 log_err("Failed formatting %s\n", u_errorName(status));
1861 return;
1862 }
1863 if (u_strcmp(expectedNeg, ubuffer) == 0) {
1864 log_err("Didn't get expected negative result\n");
1865 }
1866 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
1867 if (U_FAILURE(status) || 64 < used) {
1868 log_err("Failed formatting %s\n", u_errorName(status));
1869 return;
1870 }
1871 if (u_strcmp(expectedPos, ubuffer) == 0) {
1872 log_err("Didn't get expected positive result\n");
1873 }
1874 unum_close(nf);
1875 }
1876
TestNBSPPatternRtNum(const char * testcase,int line,UNumberFormat * nf,double myNumber)1877 static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
1878 UErrorCode status = U_ZERO_ERROR;
1879 UChar myString[20];
1880 char tmpbuf[200];
1881 double aNumber = -1.0;
1882 unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
1883 log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
1884 if(U_FAILURE(status)) {
1885 log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
1886 return;
1887 }
1888 aNumber = unum_parse(nf, myString, -1, NULL, &status);
1889 if(U_FAILURE(status)) {
1890 log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
1891 return;
1892 }
1893 if(uprv_fabs(aNumber-myNumber)>.001) {
1894 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
1895 } else {
1896 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
1897 }
1898 }
1899
TestNBSPPatternRT(const char * testcase,UNumberFormat * nf)1900 static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
1901 TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
1902 TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
1903 }
1904
TestNBSPInPattern(void)1905 static void TestNBSPInPattern(void) {
1906 UErrorCode status = U_ZERO_ERROR;
1907 UNumberFormat* nf = NULL;
1908 const char *testcase;
1909
1910
1911 testcase="ar_AE UNUM_CURRENCY";
1912 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
1913 if(U_FAILURE(status) || nf == NULL) {
1914 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
1915 return;
1916 }
1917 TestNBSPPatternRT(testcase, nf);
1918
1919 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
1920 {
1921 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
1922 UChar pat[200];
1923 testcase = "ar_AE special pattern: " SPECIAL_PATTERN;
1924 u_unescape(SPECIAL_PATTERN, pat, sizeof(pat)/sizeof(pat[0]));
1925 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
1926 if(U_FAILURE(status)) {
1927 log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status));
1928 } else {
1929 TestNBSPPatternRT(testcase, nf);
1930 }
1931 #undef SPECIAL_PATTERN
1932 }
1933 unum_close(nf); status = U_ZERO_ERROR;
1934
1935 testcase="ar_AE UNUM_DECIMAL";
1936 nf = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status);
1937 if(U_FAILURE(status)) {
1938 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
1939 }
1940 TestNBSPPatternRT(testcase, nf);
1941 unum_close(nf); status = U_ZERO_ERROR;
1942
1943 testcase="ar_AE UNUM_PERCENT";
1944 nf = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status);
1945 if(U_FAILURE(status)) {
1946 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
1947 }
1948 TestNBSPPatternRT(testcase, nf);
1949 unum_close(nf); status = U_ZERO_ERROR;
1950
1951
1952
1953 }
TestCloneWithRBNF(void)1954 static void TestCloneWithRBNF(void) {
1955 UChar pattern[1024];
1956 UChar pat2[512];
1957 UErrorCode status = U_ZERO_ERROR;
1958 UChar buffer[256];
1959 UChar buffer_cloned[256];
1960 char temp1[256];
1961 char temp2[256];
1962 UNumberFormat *pform_cloned;
1963 UNumberFormat *pform;
1964
1965 u_uastrcpy(pattern,
1966 "%main:\n"
1967 "0.x: >%%millis-only>;\n"
1968 "x.0: <%%duration<;\n"
1969 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
1970 "-x: ->>;%%millis-only:\n"
1971 "1000: 00:00.<%%millis<;\n"
1972 "%%millis-added:\n"
1973 "1000: .<%%millis<;\n"
1974 "%%millis:\n"
1975 "0: =000=;\n"
1976 "%%duration:\n"
1977 "0: =%%seconds-only=;\n"
1978 "60: =%%min-sec=;\n"
1979 "3600: =%%hr-min-sec=;\n"
1980 "86400/86400: <%%ddaayyss<[, >>];\n"
1981 "%%durationwithmillis:\n"
1982 "0: =%%seconds-only=;\n"
1983 "60: =%%min-sec=;\n"
1984 "3600: =%%hr-min-sec=;\n"
1985 "86400/86400: <%%ddaayyss<, >>;\n");
1986 u_uastrcpy(pat2,
1987 "%%seconds-only:\n"
1988 "0: 0:00:=00=;\n"
1989 "%%min-sec:\n"
1990 "0: :=00=;\n"
1991 "0/60: 0:<00<>>;\n"
1992 "%%hr-min-sec:\n"
1993 "0: :=00=;\n"
1994 "60/60: <00<>>;\n"
1995 "3600/60: <0<:>>>;\n"
1996 "%%ddaayyss:\n"
1997 "0 days;\n"
1998 "1 day;\n"
1999 "=0= days;");
2000
2001 /* This is to get around some compiler warnings about char * string length. */
2002 u_strcat(pattern, pat2);
2003
2004 pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status);
2005 unum_formatDouble(pform, 3600, buffer, 256, NULL, &status);
2006
2007 pform_cloned = unum_clone(pform,&status);
2008 unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status);
2009
2010 unum_close(pform);
2011 unum_close(pform_cloned);
2012
2013 if (u_strcmp(buffer,buffer_cloned)) {
2014 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));
2015 }
2016 }
2017
2018
TestNoExponent(void)2019 static void TestNoExponent(void) {
2020 UErrorCode status = U_ZERO_ERROR;
2021 UChar str[100];
2022 const char *cstr;
2023 UNumberFormat *fmt;
2024 int32_t pos;
2025 int32_t expect = 0;
2026 int32_t num;
2027
2028 fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status);
2029
2030 if(U_FAILURE(status) || fmt == NULL) {
2031 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status));
2032 return;
2033 }
2034
2035 cstr = "10E6";
2036 u_uastrcpy(str, cstr);
2037 expect = 10000000;
2038 pos = 0;
2039 num = unum_parse(fmt, str, -1, &pos, &status);
2040 ASSERT_TRUE(pos==4);
2041 if(U_FAILURE(status)) {
2042 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2043 } else if(expect!=num) {
2044 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2045 } else {
2046 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2047 }
2048
2049 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2050
2051 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2052 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2053
2054 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2055
2056 pos = 0;
2057 expect=10;
2058 num = unum_parse(fmt, str, -1, &pos, &status);
2059 if(num==10000000) {
2060 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr);
2061 } else if(num==expect) {
2062 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr);
2063 }
2064 ASSERT_TRUE(pos==2);
2065
2066 status = U_ZERO_ERROR;
2067
2068 unum_close(fmt);
2069
2070 /* ok, now try scientific */
2071 fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status);
2072 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status);
2073
2074 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2075
2076 cstr = "10E6";
2077 u_uastrcpy(str, cstr);
2078 expect = 10000000;
2079 pos = 0;
2080 num = unum_parse(fmt, str, -1, &pos, &status);
2081 ASSERT_TRUE(pos==4);
2082 if(U_FAILURE(status)) {
2083 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2084 } else if(expect!=num) {
2085 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2086 } else {
2087 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2088 }
2089
2090 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2091 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2092
2093 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2094
2095
2096 cstr = "10E6";
2097 u_uastrcpy(str, cstr);
2098 expect = 10000000;
2099 pos = 0;
2100 num = unum_parse(fmt, str, -1, &pos, &status);
2101 ASSERT_TRUE(pos==4);
2102 if(U_FAILURE(status)) {
2103 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2104 } else if(expect!=num) {
2105 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2106 } else {
2107 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2108 }
2109
2110 unum_close(fmt);
2111 }
2112
TestMaxInt(void)2113 static void TestMaxInt(void) {
2114 UErrorCode status = U_ZERO_ERROR;
2115 UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */
2116 UChar result1[1024] = { 0 }, result2[1024] = { 0 };
2117 int32_t len1, len2;
2118 UChar expect[] = { 0x0039, 0x0037, 0 };
2119 UNumberFormat *fmt = unum_open(
2120 UNUM_PATTERN_DECIMAL, /* style */
2121 &pattern_hash[0], /* pattern */
2122 u_strlen(pattern_hash), /* patternLength */
2123 0,
2124 0, /* parseErr */
2125 &status);
2126 if(U_FAILURE(status) || fmt == NULL) {
2127 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status));
2128 return;
2129 }
2130
2131 unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2);
2132
2133 status = U_ZERO_ERROR;
2134 /* #1 */
2135 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2136 result1[len1]=0;
2137 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2138 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2139 }
2140
2141 status = U_ZERO_ERROR;
2142 /* #2 */
2143 len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status);
2144 result2[len2]=0;
2145 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2146 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2147 }
2148
2149
2150
2151 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2152 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0);
2153
2154 unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1);
2155 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2156 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1);
2157
2158 status = U_ZERO_ERROR;
2159 /* max int digits still '2' */
2160 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2161 ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR);
2162 status = U_ZERO_ERROR;
2163
2164 /* But, formatting 97->'97' works fine. */
2165
2166 /* #1 */
2167 len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status);
2168 result1[len1]=0;
2169 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2170 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2171 }
2172
2173 status = U_ZERO_ERROR;
2174 /* #2 */
2175 len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status);
2176 result2[len2]=0;
2177 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2178 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2179 }
2180
2181
2182 unum_close(fmt);
2183 }
2184
TestUFormattable(void)2185 static void TestUFormattable(void) {
2186 UChar out2k[2048];
2187 // simple test for API docs
2188 {
2189 UErrorCode status = U_ZERO_ERROR;
2190 UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2191 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2192 //! [unum_parseToUFormattable]
2193 const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2194 int32_t result = 0;
2195 UFormattable *ufmt = ufmt_open(&status);
2196 unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status);
2197 if (ufmt_isNumeric(ufmt)) {
2198 result = ufmt_getLong(ufmt, &status); /* == 123 */
2199 } /* else { ... } */
2200 ufmt_close(ufmt);
2201 //! [unum_parseToUFormattable]
2202 assertTrue("result == 123", (result == 123));
2203 }
2204 unum_close(unum);
2205 }
2206 // test with explicitly created ufmt_open
2207 {
2208 UChar buffer[2048];
2209 UErrorCode status = U_ZERO_ERROR;
2210 UFormattable *ufmt;
2211 UNumberFormat *unum;
2212 const char *pattern = "";
2213
2214 ufmt = ufmt_open(&status);
2215 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2216 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) {
2217
2218 pattern = "31337";
2219 log_verbose("-- pattern: %s\n", pattern);
2220 u_uastrcpy(buffer, pattern);
2221 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2222 if(assertSuccess("unum_parseToUFormattable(31337)", &status)) {
2223 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337);
2224 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG);
2225 log_verbose("long = %d\n", ufmt_getLong(ufmt, &status));
2226 assertSuccess("ufmt_getLong()", &status);
2227 }
2228 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2229 if(assertSuccess("unum_formatUFormattable(31337)", &status)) {
2230 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2231 }
2232
2233 pattern = "3.14159";
2234 log_verbose("-- pattern: %s\n", pattern);
2235 u_uastrcpy(buffer, pattern);
2236 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2237 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) {
2238 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15));
2239 assertSuccess("ufmt_getDouble()", &status);
2240 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE);
2241 log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status));
2242 }
2243 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2244 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2245 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2246 }
2247 }
2248 ufmt_close(ufmt);
2249 unum_close(unum);
2250 }
2251
2252 // test with auto-generated ufmt
2253 {
2254 UChar buffer[2048];
2255 UErrorCode status = U_ZERO_ERROR;
2256 UFormattable *ufmt = NULL;
2257 UNumberFormat *unum;
2258 const char *pattern = "73476730924573500000000"; // weight of the moon, kg
2259
2260 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern);
2261 u_uastrcpy(buffer, pattern);
2262
2263 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2264 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2265
2266 ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */
2267 buffer, -1, NULL, &status);
2268 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) {
2269 log_verbose("new formattable allocated at %p\n", (void*)ufmt);
2270 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt));
2271 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2272 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2273 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2274 }
2275
2276 log_verbose("double: %g\n", ufmt_getDouble(ufmt, &status));
2277 assertSuccess("ufmt_getDouble()", &status);
2278
2279 log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status));
2280 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status));
2281 // status is now a failure due to ufmt_getLong() above.
2282 // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2283 }
2284 }
2285
2286 unum_close(unum);
2287 ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable()
2288 }
2289 }
2290
2291 typedef struct {
2292 const char* locale;
2293 const char* numsys;
2294 int32_t radix;
2295 UBool isAlgorithmic;
2296 const UChar* description;
2297 } NumSysTestItem;
2298
2299
2300 static const UChar latnDesc[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2301 static const UChar romanDesc[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2302 static const UChar arabDesc[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2303 static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2304 static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2305 static const UChar hantDesc[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2306 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2307 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2308
2309 static const NumSysTestItem numSysTestItems[] = {
2310 //locale numsys radix isAlgo description
2311 { "en", "latn", 10, FALSE, latnDesc },
2312 { "en@numbers=roman", "roman", 10, TRUE, romanDesc },
2313 { "en@numbers=finance", "latn", 10, FALSE, latnDesc },
2314 { "ar", "arab", 10, FALSE, arabDesc },
2315 { "fa", "arabext", 10, FALSE, arabextDesc },
2316 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE, hanidecDesc },
2317 { "zh_Hant@numbers=traditional", "hant", 10, TRUE, hantDesc },
2318 { NULL, NULL, 0, FALSE, NULL },
2319 };
2320 enum { kNumSysDescripBufMax = 64 };
2321
TestUNumberingSystem(void)2322 static void TestUNumberingSystem(void) {
2323 const NumSysTestItem * itemPtr;
2324 UNumberingSystem * unumsys;
2325 UEnumeration * uenum;
2326 const char * numsys;
2327 UErrorCode status;
2328
2329 for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) {
2330 status = U_ZERO_ERROR;
2331 unumsys = unumsys_open(itemPtr->locale, &status);
2332 if ( U_SUCCESS(status) ) {
2333 UChar ubuf[kNumSysDescripBufMax];
2334 int32_t ulen, radix = unumsys_getRadix(unumsys);
2335 UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys);
2336 numsys = unumsys_getName(unumsys);
2337 if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) {
2338 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2339 itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic);
2340 }
2341 ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status);
2342 if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) {
2343 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status));
2344 }
2345 unumsys_close(unumsys);
2346 } else {
2347 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status));
2348 }
2349 }
2350
2351 status = U_ZERO_ERROR;
2352 uenum = unumsys_openAvailableNames(&status);
2353 if ( U_SUCCESS(status) ) {
2354 int32_t numsysCount = 0;
2355 // sanity check for a couple of number systems that must be in the enumeration
2356 UBool foundLatn = FALSE;
2357 UBool foundArab = FALSE;
2358 while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
2359 status = U_ZERO_ERROR;
2360 unumsys = unumsys_openByName(numsys, &status);
2361 if ( U_SUCCESS(status) ) {
2362 numsysCount++;
2363 if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
2364 if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
2365 unumsys_close(unumsys);
2366 } else {
2367 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2368 numsys, myErrorName(status));
2369 }
2370 }
2371 uenum_close(uenum);
2372 if ( numsysCount < 40 || !foundLatn || !foundArab ) {
2373 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2374 numsysCount, foundLatn, foundArab);
2375 }
2376 } else {
2377 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
2378 }
2379 }
2380
2381 #endif /* #if !UCONFIG_NO_FORMATTING */
2382