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