]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/cintltst/cnumtst.c
ICU-62123.0.1.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cnumtst.c
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8 /********************************************************************************
9 *
10 * File CNUMTST.C
11 *
12 * Madhu Katragadda Creation
13 *
14 * Modification History:
15 *
16 * Date Name Description
17 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
18 * 07/15/99 helena Ported to HPUX 10/11 CC.
19 *********************************************************************************
20 */
21
22 /* C API TEST FOR NUMBER FORMAT */
23
24 #include "unicode/utypes.h"
25
26 #if !UCONFIG_NO_FORMATTING
27
28 #include "unicode/uloc.h"
29 #include "unicode/umisc.h"
30 #include "unicode/unum.h"
31 #include "unicode/unumsys.h"
32 #include "unicode/ustring.h"
33 #include "unicode/udisplaycontext.h"
34
35 #include "cintltst.h"
36 #include "cnumtst.h"
37 #include "cmemory.h"
38 #include "cstring.h"
39 #include "putilimp.h"
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 static const char *tagAssert(const char *f, int32_t l, const char *msg) {
44 static char _fileline[1000];
45 sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg);
46 return _fileline;
47 }
48
49 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
50
51 void addNumForTest(TestNode** root);
52 static void TestTextAttributeCrash(void);
53 static void TestNBSPInPattern(void);
54 static void TestInt64Parse(void);
55 static void TestParseCurrency(void);
56 static void TestMaxInt(void);
57 static void TestNoExponent(void);
58 static void TestUFormattable(void);
59 static void TestUNumberingSystem(void);
60 static void TestCurrencyIsoPluralFormat(void);
61 static void TestContext(void);
62 static void TestCurrencyUsage(void);
63 static void TestCurrFmtNegSameAsPositive(void);
64 static void TestVariousStylesAndAttributes(void);
65 static void TestParseCurrPatternWithDecStyle(void);
66 static void TestFormatForFields(void);
67 static void TestRBNFRounding(void);
68 static void Test12052_NullPointer(void);
69 static void TestParseAltNum(void);
70 static void TestParseCurrPatternWithDecStyle(void);
71 static void TestParseCases(void);
72 static void TestFormatPrecision(void);
73
74 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
75
76 void addNumForTest(TestNode** root)
77 {
78 TESTCASE(TestNumberFormat);
79 TESTCASE(TestSpelloutNumberParse);
80 TESTCASE(TestSignificantDigits);
81 TESTCASE(TestSigDigRounding);
82 TESTCASE(TestNumberFormatPadding);
83 TESTCASE(TestInt64Format);
84 TESTCASE(TestNonExistentCurrency);
85 TESTCASE(TestCurrencyRegression);
86 TESTCASE(TestTextAttributeCrash);
87 TESTCASE(TestRBNFFormat);
88 TESTCASE(TestRBNFRounding);
89 TESTCASE(TestNBSPInPattern);
90 TESTCASE(TestInt64Parse);
91 TESTCASE(TestParseZero);
92 TESTCASE(TestParseCurrency);
93 TESTCASE(TestCloneWithRBNF);
94 TESTCASE(TestMaxInt);
95 TESTCASE(TestNoExponent);
96 TESTCASE(TestUFormattable);
97 TESTCASE(TestUNumberingSystem);
98 TESTCASE(TestCurrencyIsoPluralFormat);
99 TESTCASE(TestContext);
100 TESTCASE(TestCurrencyUsage);
101 TESTCASE(TestCurrFmtNegSameAsPositive);
102 TESTCASE(TestVariousStylesAndAttributes);
103 TESTCASE(TestParseCurrPatternWithDecStyle);
104 TESTCASE(TestFormatForFields);
105 //TESTCASE(Test12052_NullPointer);
106 TESTCASE(TestParseAltNum);
107 TESTCASE(TestParseCurrPatternWithDecStyle);
108 TESTCASE(TestParseCases);
109 TESTCASE(TestFormatPrecision);
110 }
111
112 /* test Parse int 64 */
113
114 static void TestInt64Parse()
115 {
116
117 UErrorCode st = U_ZERO_ERROR;
118 UErrorCode* status = &st;
119
120 const char* st1 = "009223372036854775808";
121 const int size = 21;
122 UChar text[21];
123
124
125 UNumberFormat* nf;
126
127 int64_t a;
128
129 u_charsToUChars(st1, text, size);
130 nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status);
131
132 if(U_FAILURE(*status))
133 {
134 log_data_err("Error in unum_open() %s \n", myErrorName(*status));
135 return;
136 }
137
138 log_verbose("About to test unum_parseInt64() with out of range number\n");
139
140 a = unum_parseInt64(nf, text, size, 0, status);
141 (void)a; /* Suppress set but not used warning. */
142
143
144 if(!U_FAILURE(*status))
145 {
146 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status));
147 }
148 else
149 {
150 log_verbose("unum_parseInt64() successful\n");
151 }
152
153 unum_close(nf);
154 return;
155 }
156
157 /* test Number Format API */
158 static void TestNumberFormat()
159 {
160 UChar *result=NULL;
161 UChar temp1[512];
162 UChar temp2[512];
163
164 UChar temp[5];
165
166 UChar prefix[5];
167 UChar suffix[5];
168 UChar symbol[20];
169 int32_t resultlength;
170 int32_t resultlengthneeded;
171 int32_t parsepos;
172 double d1 = -1.0;
173 int32_t l1;
174 double d = -10456.37;
175 double a = 1234.56, a1 = 1235.0;
176 int32_t l = 100000000;
177 UFieldPosition pos1;
178 UFieldPosition pos2;
179 int32_t numlocales;
180 int32_t i;
181
182 UNumberFormatAttribute attr;
183 UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL;
184 int32_t newvalue;
185 UErrorCode status=U_ZERO_ERROR;
186 UNumberFormatStyle style= UNUM_DEFAULT;
187 UNumberFormat *pattern;
188 UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr,
189 *cur_frpattern, *myclone, *spellout_def;
190
191 /* Testing unum_open() with various Numberformat styles and locales*/
192 status = U_ZERO_ERROR;
193 log_verbose("Testing unum_open() with default style and locale\n");
194 def=unum_open(style, NULL,0,NULL, NULL,&status);
195
196 /* Might as well pack it in now if we can't even get a default NumberFormat... */
197 if(U_FAILURE(status))
198 {
199 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
200 return;
201 }
202
203 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
204 fr=unum_open(style,NULL,0, "fr_FR",NULL, &status);
205 if(U_FAILURE(status))
206 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status));
207
208 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
209 style=UNUM_CURRENCY;
210 /* Can't hardcode the result to assume the default locale is "en_US". */
211 cur_def=unum_open(style, NULL,0,"en_US", NULL, &status);
212 if(U_FAILURE(status))
213 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
214 myErrorName(status) );
215
216 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
217 cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status);
218 if(U_FAILURE(status))
219 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
220 myErrorName(status));
221
222 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
223 style=UNUM_PERCENT;
224 per_def=unum_open(style,NULL,0, NULL,NULL, &status);
225 if(U_FAILURE(status))
226 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status));
227
228 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
229 per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status);
230 if(U_FAILURE(status))
231 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status));
232
233 log_verbose("\nTesting unum_open(spellout, NULL, status)");
234 style=UNUM_SPELLOUT;
235 spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status);
236 if(U_FAILURE(status))
237 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status));
238
239 /* Testing unum_clone(..) */
240 log_verbose("\nTesting unum_clone(fmt, status)");
241 status = U_ZERO_ERROR;
242 myclone = unum_clone(def,&status);
243 if(U_FAILURE(status))
244 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status));
245 else
246 {
247 log_verbose("unum_clone() successful\n");
248 }
249
250 /*Testing unum_getAvailable() and unum_countAvailable()*/
251 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
252 numlocales=unum_countAvailable();
253 if(numlocales < 0)
254 log_err("error in countAvailable");
255 else{
256 log_verbose("unum_countAvialable() successful\n");
257 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales);
258 }
259 for(i=0;i<numlocales;i++)
260 {
261 log_verbose("%s\n", unum_getAvailable(i));
262 if (unum_getAvailable(i) == 0)
263 log_err("No locale for which number formatting patterns are applicable\n");
264 else
265 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i));
266 }
267
268
269 /*Testing unum_format() and unum_formatdouble()*/
270 u_uastrcpy(temp1, "$100,000,000.00");
271
272 log_verbose("\nTesting unum_format() \n");
273 resultlength=0;
274 pos1.field = UNUM_INTEGER_FIELD;
275 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &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_format(cur_def, l, result, resultlength, &pos1, &status);
284 }
285 }
286
287 if(U_FAILURE(status))
288 {
289 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) );
290 }
291 if(u_strcmp(result, temp1)==0)
292 log_verbose("Pass: Number formatting using unum_format() successful\n");
293 else
294 log_err("Fail: Error in number Formatting using unum_format()\n");
295 if(pos1.beginIndex == 1 && pos1.endIndex == 12)
296 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
297 else
298 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
299 pos1.beginIndex, pos1.endIndex);
300
301 free(result);
302 result = 0;
303
304 log_verbose("\nTesting unum_formatDouble()\n");
305 u_uastrcpy(temp1, "-$10,456.37");
306 resultlength=0;
307 pos2.field = UNUM_FRACTION_FIELD;
308 resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status);
309 if(status==U_BUFFER_OVERFLOW_ERROR)
310 {
311 status=U_ZERO_ERROR;
312 resultlength=resultlengthneeded+1;
313 result=(UChar*)malloc(sizeof(UChar) * resultlength);
314 /* for (i = 0; i < 100000; i++) */
315 {
316 unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status);
317 }
318 }
319 if(U_FAILURE(status))
320 {
321 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
322 }
323 if(result && u_strcmp(result, temp1)==0)
324 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
325 else {
326 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
327 aescstrdup(result, -1), aescstrdup(temp1, -1));
328 }
329 if(pos2.beginIndex == 9 && pos2.endIndex == 11)
330 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
331 else
332 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
333 pos1.beginIndex, pos1.endIndex);
334
335
336 /* Testing unum_parse() and unum_parseDouble() */
337 log_verbose("\nTesting unum_parseDouble()\n");
338 /* for (i = 0; i < 100000; i++)*/
339 parsepos=0;
340 if (result != NULL) {
341 d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status);
342 } else {
343 log_err("result is NULL\n");
344 }
345 if(U_FAILURE(status)) {
346 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status));
347 }
348
349 if(d1!=d)
350 log_err("Fail: Error in parsing\n");
351 else
352 log_verbose("Pass: parsing successful\n");
353 if (result)
354 free(result);
355 result = 0;
356
357 status = U_ZERO_ERROR;
358 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
359 log_verbose("\nTesting unum_formatDoubleCurrency\n");
360 u_uastrcpy(temp1, "Y1,235");
361 temp1[0] = 0xA5; /* Yen sign */
362 u_uastrcpy(temp, "JPY");
363 resultlength=0;
364 pos2.field = UNUM_INTEGER_FIELD;
365 resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status);
366 if (status==U_BUFFER_OVERFLOW_ERROR) {
367 status=U_ZERO_ERROR;
368 resultlength=resultlengthneeded+1;
369 result=(UChar*)malloc(sizeof(UChar) * resultlength);
370 unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status);
371 }
372 if (U_FAILURE(status)) {
373 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
374 }
375 if (result && u_strcmp(result, temp1)==0) {
376 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
377 } else {
378 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
379 aescstrdup(result, -1), aescstrdup(temp1, -1));
380 }
381 if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
382 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
383 } else {
384 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
385 pos1.beginIndex, pos1.endIndex);
386 }
387
388 log_verbose("\nTesting unum_parseDoubleCurrency\n");
389 parsepos=0;
390 if (result == NULL) {
391 log_err("result is NULL\n");
392 }
393 else {
394 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
395 if (U_FAILURE(status)) {
396 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
397 }
398 /* Note: a==1234.56, but on parse expect a1=1235.0 */
399 if (d1!=a1) {
400 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1);
401 } else {
402 log_verbose("Pass: parsed currency amount successfully\n");
403 }
404 if (u_strcmp(temp2, temp)==0) {
405 log_verbose("Pass: parsed correct currency\n");
406 } else {
407 log_err("Fail: parsed incorrect currency\n");
408 }
409 }
410 status = U_ZERO_ERROR; /* reset */
411
412 free(result);
413 result = 0;
414
415
416 /* performance testing */
417 u_uastrcpy(temp1, "$462.12345");
418 resultlength=u_strlen(temp1);
419 /* for (i = 0; i < 100000; i++) */
420 {
421 parsepos=0;
422 d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status);
423 }
424 if(U_FAILURE(status))
425 {
426 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
427 }
428
429 /*
430 * Note: "for strict standard conformance all operations and constants are now supposed to be
431 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
432 */
433 a1 = 462.12345;
434
435 if(d1!=a1)
436 log_err("Fail: Error in parsing\n");
437 else
438 log_verbose("Pass: parsing successful\n");
439
440 free(result);
441
442 u_uastrcpy(temp1, "($10,456.3E1])");
443 parsepos=0;
444 d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status);
445 if(U_SUCCESS(status))
446 {
447 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status));
448 }
449
450
451 log_verbose("\nTesting unum_format()\n");
452 status=U_ZERO_ERROR;
453 resultlength=0;
454 parsepos=0;
455 resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status);
456 if(status==U_BUFFER_OVERFLOW_ERROR)
457 {
458 status=U_ZERO_ERROR;
459 resultlength=resultlengthneeded+1;
460 result=(UChar*)malloc(sizeof(UChar) * resultlength);
461 /* for (i = 0; i < 100000; i++)*/
462 {
463 unum_format(per_fr, l, result, resultlength, &pos1, &status);
464 }
465 }
466 if(U_FAILURE(status))
467 {
468 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
469 }
470
471
472 log_verbose("\nTesting unum_parse()\n");
473 /* for (i = 0; i < 100000; i++) */
474 {
475 parsepos=0;
476 l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status);
477 }
478 if(U_FAILURE(status))
479 {
480 log_err("parse failed. The error is : %s\n", myErrorName(status));
481 }
482
483 if(l1!=l)
484 log_err("Fail: Error in parsing\n");
485 else
486 log_verbose("Pass: parsing successful\n");
487
488 free(result);
489
490 /* create a number format using unum_openPattern(....)*/
491 log_verbose("\nTesting unum_openPattern()\n");
492 u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)");
493 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
494 if(U_FAILURE(status))
495 {
496 log_err("error in unum_openPattern(): %s\n", myErrorName(status) );;
497 }
498 else
499 log_verbose("Pass: unum_openPattern() works fine\n");
500
501 /*test for unum_toPattern()*/
502 log_verbose("\nTesting unum_toPattern()\n");
503 resultlength=0;
504 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
505 if(status==U_BUFFER_OVERFLOW_ERROR)
506 {
507 status=U_ZERO_ERROR;
508 resultlength=resultlengthneeded+1;
509 result=(UChar*)malloc(sizeof(UChar) * resultlength);
510 unum_toPattern(pattern, FALSE, result, resultlength, &status);
511 }
512 if(U_FAILURE(status))
513 {
514 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
515 }
516 else
517 {
518 if(u_strcmp(result, temp1)!=0)
519 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
520 else
521 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
522 free(result);
523 }
524
525 /*Testing unum_getSymbols() and unum_setSymbols()*/
526 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
527 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
528 resultlength=0;
529 resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &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_toPattern(cur_def, FALSE, result, resultlength, &status);
536 }
537 if(U_FAILURE(status))
538 {
539 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
540 }
541
542 status=U_ZERO_ERROR;
543 cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status);
544 if(U_FAILURE(status))
545 {
546 log_err("error in unum_openPattern(): %s\n", myErrorName(status));
547 }
548
549 free(result);
550
551 /*getting the symbols of cur_def */
552 /*set the symbols of cur_frpattern to cur_def */
553 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
554 status=U_ZERO_ERROR;
555 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
556 unum_setSymbol(cur_frpattern, symType, temp1, -1, &status);
557 if(U_FAILURE(status))
558 {
559 log_err("Error in get/set symbols: %s\n", myErrorName(status));
560 }
561 }
562
563 /*format to check the result */
564 resultlength=0;
565 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
566 if(status==U_BUFFER_OVERFLOW_ERROR)
567 {
568 status=U_ZERO_ERROR;
569 resultlength=resultlengthneeded+1;
570 result=(UChar*)malloc(sizeof(UChar) * resultlength);
571 unum_format(cur_def, l, result, resultlength, &pos1, &status);
572 }
573 if(U_FAILURE(status))
574 {
575 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
576 }
577
578 if(U_FAILURE(status)){
579 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status));
580 }
581 unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL);
582
583 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
584 status=U_ZERO_ERROR;
585 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
586 unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status);
587 if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0)
588 {
589 log_err("Fail: error in getting symbols\n");
590 }
591 else
592 log_verbose("Pass: get and set symbols successful\n");
593 }
594
595 /*format and check with the previous result */
596
597 resultlength=0;
598 resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status);
599 if(status==U_BUFFER_OVERFLOW_ERROR)
600 {
601 status=U_ZERO_ERROR;
602 resultlength=resultlengthneeded+1;
603 unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status);
604 }
605 if(U_FAILURE(status))
606 {
607 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
608 }
609 /* TODO:
610 * This test fails because we have not called unum_applyPattern().
611 * Currently, such an applyPattern() does not exist on the C API, and
612 * we have jitterbug 411 for it.
613 * Since it is close to the 1.5 release, I (markus) am disabling this test just
614 * for this release (I added the test itself only last week).
615 * For the next release, we need to fix this.
616 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
617 */
618 if(u_strcmp(result, temp1) != 0) {
619 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1);
620 }
621
622
623 /*----------- */
624
625 free(result);
626
627 /* Testing unum_get/setSymbol() */
628 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
629 symbol[0] = (UChar)(0x41 + i);
630 symbol[1] = (UChar)(0x61 + i);
631 unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status);
632 if(U_FAILURE(status)) {
633 log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status));
634 return;
635 }
636 }
637 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
638 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
639 if(U_FAILURE(status)) {
640 log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status));
641 return;
642 }
643 if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) {
644 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i);
645 }
646 }
647 /*try getting from a bogus symbol*/
648 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
649 if(U_SUCCESS(status)){
650 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
651 }
652 if(U_FAILURE(status)){
653 if(status != U_ILLEGAL_ARGUMENT_ERROR){
654 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status));
655 }
656 }
657 status=U_ZERO_ERROR;
658
659 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
660 log_verbose("\nTesting getting and setting text attributes\n");
661 resultlength=5;
662 unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
663 if(U_FAILURE(status))
664 {
665 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
666 }
667 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
668 if(U_FAILURE(status))
669 {
670 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
671 }
672 unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status);
673 if(U_FAILURE(status))
674 {
675 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
676 }
677 if(u_strcmp(suffix,temp)!=0)
678 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
679 else
680 log_verbose("Pass: setting and getting suffix works fine\n");
681 /*set it back to normal */
682 u_uastrcpy(temp,"$");
683 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
684
685 /*checking some more text setter conditions */
686 u_uastrcpy(prefix, "+");
687 unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status);
688 if(U_FAILURE(status))
689 {
690 log_err("error in setting the text attributes : %s\n", myErrorName(status));
691 }
692 unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status);
693 if(U_FAILURE(status))
694 {
695 log_err("error in getting the text attributes : %s\n", myErrorName(status));
696 }
697
698 if(u_strcmp(prefix, temp)!=0)
699 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
700 else
701 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
702
703 u_uastrcpy(prefix, "+");
704 unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status);
705 if(U_FAILURE(status))
706 {
707 log_err("error in setting the text attributes : %s\n", myErrorName(status));
708 }
709 unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status);
710 if(U_FAILURE(status))
711 {
712 log_err("error in getting the text attributes : %s\n", myErrorName(status));
713 }
714 if(u_strcmp(prefix, temp)!=0)
715 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
716 else
717 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
718
719 u_uastrcpy(suffix, "+");
720 unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
721 if(U_FAILURE(status))
722 {
723 log_err("error in setting the text attributes: %s\n", myErrorName(status));
724 }
725
726 unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
727 if(U_FAILURE(status))
728 {
729 log_err("error in getting the text attributes : %s\n", myErrorName(status));
730 }
731 if(u_strcmp(suffix, temp)!=0)
732 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
733 else
734 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
735
736 u_uastrcpy(suffix, "++");
737 unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
738 if(U_FAILURE(status))
739 {
740 log_err("error in setting the text attributes: %s\n", myErrorName(status));
741 }
742
743 unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status);
744 if(U_FAILURE(status))
745 {
746 log_err("error in getting the text attributes : %s\n", myErrorName(status));
747 }
748 if(u_strcmp(suffix, temp)!=0)
749 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
750 else
751 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
752
753 /*Testing unum_getAttribute and unum_setAttribute() */
754 log_verbose("\nTesting get and set Attributes\n");
755 attr=UNUM_GROUPING_SIZE;
756 newvalue=unum_getAttribute(def, attr);
757 newvalue=2;
758 unum_setAttribute(def, attr, newvalue);
759 if(unum_getAttribute(def,attr)!=2)
760 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
761 else
762 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
763
764 attr=UNUM_MULTIPLIER;
765 newvalue=unum_getAttribute(def, attr);
766 newvalue=8;
767 unum_setAttribute(def, attr, newvalue);
768 if(unum_getAttribute(def,attr) != 8)
769 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
770 else
771 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
772
773 attr=UNUM_SECONDARY_GROUPING_SIZE;
774 newvalue=unum_getAttribute(def, attr);
775 newvalue=2;
776 unum_setAttribute(def, attr, newvalue);
777 if(unum_getAttribute(def,attr) != 2)
778 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
779 unum_getAttribute(def,attr));
780 else
781 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
782
783 /*testing set and get Attributes extensively */
784 log_verbose("\nTesting get and set attributes extensively\n");
785 for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) )
786 {
787 newvalue=unum_getAttribute(fr, attr);
788 unum_setAttribute(def, attr, newvalue);
789 if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr))
790 log_err("error in setting and getting attributes\n");
791 else
792 log_verbose("Pass: attributes set and retrieved successfully\n");
793 }
794
795 /*testing spellout format to make sure we can use it successfully.*/
796 log_verbose("\nTesting spellout format\n");
797 if (spellout_def)
798 {
799 static const int32_t values[] = { 0, -5, 105, 1005, 105050 };
800 for (i = 0; i < UPRV_LENGTHOF(values); ++i) {
801 UChar buffer[128];
802 int32_t len;
803 int32_t value = values[i];
804 status = U_ZERO_ERROR;
805 len = unum_format(spellout_def, value, buffer, UPRV_LENGTHOF(buffer), NULL, &status);
806 if(U_FAILURE(status)) {
807 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
808 } else {
809 int32_t pp = 0;
810 int32_t parseResult;
811 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
812 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
813
814 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status);
815 if (U_FAILURE(status)) {
816 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
817 } else if (parseResult != value) {
818 log_err("unum_format result %d != value %d\n", parseResult, value);
819 }
820 }
821 }
822 }
823 else {
824 log_err("Spellout format is unavailable\n");
825 }
826
827 { /* Test for ticket #7079 */
828 UNumberFormat* dec_en;
829 UChar groupingSep[] = { 0 };
830 UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
831 double parseResult = 0.0;
832
833 status=U_ZERO_ERROR;
834 dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
835 unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0);
836 unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status);
837 parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status);
838 /* Without the fix in #7079, the above call will hang */
839 if ( U_FAILURE(status) || parseResult != 12.0 ) {
840 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
841 myErrorName(status), parseResult);
842 } else {
843 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
844 }
845 unum_close(dec_en);
846 }
847
848 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
849 to verify that it is taking the pure decimal path. */
850 UNumberFormat *fmt;
851 const char *bdpattern = "#,##0.#########";
852 const char *numInitial = "12345678900987654321.1234567896";
853 const char *numFormatted = "12,345,678,900,987,654,321.12345679";
854 const char *parseExpected = "12345678900987654321.12345679";
855 const char *parseExpected2 = "345678900987654321.12345679";
856 int32_t resultSize = 0;
857 int32_t parsePos = 0; /* Output parameter for Parse operations. */
858 #define DESTCAPACITY 100
859 UChar dest[DESTCAPACITY];
860 char desta[DESTCAPACITY];
861 UFieldPosition fieldPos = {0};
862
863 /* Format */
864
865 status = U_ZERO_ERROR;
866 u_uastrcpy(dest, bdpattern);
867 fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status);
868 if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
869
870 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status);
871 if (U_FAILURE(status)) {
872 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
873 }
874 u_austrncpy(desta, dest, DESTCAPACITY);
875 if (strcmp(numFormatted, desta) != 0) {
876 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
877 __FILE__, __LINE__, numFormatted, desta);
878 }
879 if (strlen(numFormatted) != resultSize) {
880 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
881 __FILE__, __LINE__, strlen(numFormatted), resultSize);
882 }
883
884 /* Format with a FieldPosition parameter */
885
886 fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
887 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status);
888 if (U_FAILURE(status)) {
889 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
890 }
891 u_austrncpy(desta, dest, DESTCAPACITY);
892 if (strcmp(numFormatted, desta) != 0) {
893 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
894 __FILE__, __LINE__, numFormatted, desta);
895 }
896 if (fieldPos.beginIndex != 26) { /* index of "." in formatted number */
897 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
898 __FILE__, __LINE__, 0, fieldPos.beginIndex);
899 }
900 if (fieldPos.endIndex != 27) {
901 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
902 __FILE__, __LINE__, 0, fieldPos.endIndex);
903 }
904
905 /* Parse */
906
907 status = U_ZERO_ERROR;
908 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
909 resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status);
910 if (U_FAILURE(status)) {
911 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
912 }
913 if (uprv_strcmp(parseExpected, desta) != 0) {
914 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
915 __FILE__, __LINE__, parseExpected, desta);
916 } else {
917 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
918 __FILE__, __LINE__, desta);
919 }
920 if (strlen(parseExpected) != resultSize) {
921 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
922 __FILE__, __LINE__, strlen(parseExpected), resultSize);
923 }
924
925 /* Parse with a parsePos parameter */
926
927 status = U_ZERO_ERROR;
928 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
929 parsePos = 3; /* 12,345,678,900,987,654,321.12345679 */
930 /* start parsing at the the third char */
931 resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status);
932 if (U_FAILURE(status)) {
933 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
934 }
935 if (strcmp(parseExpected2, desta) != 0) { /* "345678900987654321.12345679" */
936 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
937 __FILE__, __LINE__, parseExpected2, desta);
938 } else {
939 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
940 __FILE__, __LINE__, desta);
941 }
942 if (strlen(numFormatted) != parsePos) {
943 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
944 __FILE__, __LINE__, strlen(parseExpected), parsePos);
945 }
946
947 unum_close(fmt);
948 }
949
950 status = U_ZERO_ERROR;
951 /* Test invalid symbol argument */
952 {
953 int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1;
954 int32_t badsymbolSmall = -1;
955 UChar value[10];
956 int32_t valueLength = 10;
957 UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
958 if (U_FAILURE(status)) {
959 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
960 } else {
961 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status);
962 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
963
964 status = U_ZERO_ERROR;
965 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status);
966 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
967
968 status = U_ZERO_ERROR;
969 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status);
970 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
971
972 status = U_ZERO_ERROR;
973 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status);
974 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
975
976 unum_close(fmt);
977 }
978 }
979
980
981 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
982 unum_close(def);
983 unum_close(fr);
984 unum_close(cur_def);
985 unum_close(cur_fr);
986 unum_close(per_def);
987 unum_close(per_fr);
988 unum_close(spellout_def);
989 unum_close(pattern);
990 unum_close(cur_frpattern);
991 unum_close(myclone);
992
993 }
994
995 static void TestParseZero(void)
996 {
997 UErrorCode errorCode = U_ZERO_ERROR;
998 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */
999 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
1000 double dbl;
1001
1002 #if 0
1003 UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode);
1004 #else
1005 UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode);
1006 #endif
1007
1008 dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode );
1009 if (U_FAILURE(errorCode)) {
1010 log_data_err("Result - %s\n", u_errorName(errorCode));
1011 } else {
1012 log_verbose("Double: %f\n", dbl);
1013 }
1014 unum_close(unum);
1015 }
1016
1017 static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
1018 static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */
1019 static const UChar dollarsUS4Sym[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
1020 static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
1021 static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
1022 static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */
1023 static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
1024 static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
1025 static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
1026 static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
1027 static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
1028 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 */
1029 static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
1030 static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
1031
1032 typedef struct {
1033 const char * locale;
1034 const char * descrip;
1035 const UChar * currStr;
1036 const UChar * plurStr;
1037 UErrorCode parsDoubExpectErr;
1038 int32_t parsDoubExpectPos;
1039 double parsDoubExpectVal;
1040 UErrorCode parsCurrExpectErr;
1041 int32_t parsCurrExpectPos;
1042 double parsCurrExpectVal;
1043 const char * parsCurrExpectCurr;
1044 } ParseCurrencyItem;
1045
1046 static const ParseCurrencyItem parseCurrencyItems[] = {
1047 { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" },
1048 { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" },
1049 { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1050 { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1051 { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1052 { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1053 { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1054
1055 { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1056 { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1057 { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1058 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, "" },
1059 { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1060 { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1061 { "en_GB", "dollars4", dollarsUS4Sym,dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 4, 4.0, "USD" },
1062
1063 { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" },
1064 { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" },
1065 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1066 { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1067 { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1068
1069 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL }
1070 };
1071
1072 static void TestParseCurrency()
1073 {
1074 const ParseCurrencyItem * itemPtr;
1075 for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) {
1076 UNumberFormat* unum;
1077 UErrorCode status;
1078 double parseVal;
1079 int32_t parsePos;
1080 UChar parseCurr[4];
1081 char parseCurrB[4];
1082
1083 status = U_ZERO_ERROR;
1084 unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
1085 if (U_SUCCESS(status)) {
1086 const UChar * currStr = itemPtr->currStr;
1087 status = U_ZERO_ERROR;
1088 parsePos = 0;
1089 parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status);
1090 if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
1091 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1092 itemPtr->locale, itemPtr->descrip,
1093 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
1094 u_errorName(status), parsePos, parseVal );
1095 }
1096 status = U_ZERO_ERROR;
1097 parsePos = 0;
1098 parseCurr[0] = 0;
1099 parseVal = unum_parseDoubleCurrency(unum, currStr, -1, &parsePos, parseCurr, &status);
1100 u_austrncpy(parseCurrB, parseCurr, 4);
1101 if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal ||
1102 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1103 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1104 itemPtr->locale, itemPtr->descrip,
1105 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1106 u_errorName(status), parsePos, parseVal, parseCurrB );
1107 }
1108 unum_close(unum);
1109 } else {
1110 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1111 }
1112
1113 if (itemPtr->plurStr != NULL) {
1114 status = U_ZERO_ERROR;
1115 unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status);
1116 if (U_SUCCESS(status)) {
1117 status = U_ZERO_ERROR;
1118 parsePos = 0;
1119 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
1120 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
1121 log_err("UNUM_CURRENCY parseDouble Plural %s/%s, expect %s val %.1f, get %s val %.1f\n",
1122 itemPtr->locale, itemPtr->descrip,
1123 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
1124 u_errorName(status), parseVal );
1125 }
1126 status = U_ZERO_ERROR;
1127 parsePos = 0;
1128 parseCurr[0] = 0;
1129 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status);
1130 u_austrncpy(parseCurrB, parseCurr, 4);
1131 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal ||
1132 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1133 log_err("UNUM_CURRENCY parseDoubleCurrency Plural %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1134 itemPtr->locale, itemPtr->descrip,
1135 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1136 u_errorName(status), parseVal, parseCurrB );
1137 }
1138 unum_close(unum);
1139 } else {
1140 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1141 }
1142 }
1143 }
1144 }
1145
1146 typedef struct {
1147 const char * testname;
1148 const char * locale;
1149 UBool lenient;
1150 const UChar * source;
1151 int32_t startPos;
1152 int32_t value;
1153 int32_t endPos;
1154 UErrorCode status;
1155 } NumParseTestItem;
1156
1157 static const UChar ustr_zh50d[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1158 static const UChar ustr_zh05a[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1159 static const UChar ustr_zh05d[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1160
1161 static const NumParseTestItem altnumParseTests[] = {
1162 /* name loc lenent src start val end status */
1163 { "zh@hd,50dL","zh@numbers=hanidec", TRUE, ustr_zh50d, 0, 50, 2, U_USING_DEFAULT_WARNING },
1164 { "zh@hd,05aL","zh@numbers=hanidec", TRUE, ustr_zh05a, 0, 5, 2, U_USING_DEFAULT_WARNING },
1165 { "zh@hd,05dL","zh@numbers=hanidec", TRUE, ustr_zh05d, 0, 5, 2, U_USING_DEFAULT_WARNING },
1166 { NULL, NULL, FALSE, NULL, 0, 0, 0, 0 } /* terminator */
1167 };
1168
1169 static void TestParseAltNum(void)
1170 {
1171 const NumParseTestItem * testPtr;
1172 for (testPtr = altnumParseTests; testPtr->testname != NULL; ++testPtr) {
1173 UErrorCode status = U_ZERO_ERROR;
1174 int32_t value, position = testPtr->startPos;
1175 UNumberFormat *nf = unum_open(UNUM_DECIMAL, NULL, 0, testPtr->locale, NULL, &status);
1176 if (U_FAILURE(status)) {
1177 log_err_status(status, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1178 continue;
1179 }
1180 unum_setAttribute(nf, UNUM_LENIENT_PARSE, testPtr->lenient);
1181 value = unum_parse(nf, testPtr->source, -1, &position, &status);
1182 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1183 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1184 testPtr->locale, testPtr->testname, testPtr->startPos,
1185 testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1186 value, position, myErrorName(status) );
1187 }
1188 unum_close(nf);
1189 }
1190 }
1191
1192 static const UChar ustr_en0[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1193 static const UChar ustr_123[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1194 static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1195 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1196 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1197 static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1198 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
1199 static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1200 static const UChar ustr_zh50s[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1201 //static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1202 //static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1203 //static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1204
1205 #define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1206
1207 static const NumParseTestItem spelloutParseTests[] = {
1208 /* name loc lenent src start val end status */
1209 { "en0", "en", FALSE, ustr_en0, 0, 0, 4, U_ZERO_ERROR },
1210 { "en0", "en", FALSE, ustr_en0, 2, 0, 2, U_PARSE_ERROR },
1211 { "en0", "ja", FALSE, ustr_en0, 0, 0, 0, U_PARSE_ERROR },
1212 #if NUMERIC_STRINGS_NOT_PARSEABLE
1213 { "123", "en", FALSE, ustr_123, 0, 0, 0, U_PARSE_ERROR },
1214 #else
1215 { "123", "en", FALSE, ustr_123, 0, 123, 3, U_ZERO_ERROR },
1216 #endif
1217 { "123L", "en", TRUE, ustr_123, 0, 123, 3, U_ZERO_ERROR },
1218 { "en123", "en", FALSE, ustr_en123, 0, 123, 24, U_ZERO_ERROR },
1219 { "en123", "en", FALSE, ustr_en123, 12, 23, 24, U_ZERO_ERROR },
1220 { "en123", "fr", FALSE, ustr_en123, 16, 0, 16, U_PARSE_ERROR },
1221 { "fr123", "fr", FALSE, ustr_fr123, 0, 123, 16, U_ZERO_ERROR },
1222 { "fr123", "fr", FALSE, ustr_fr123, 5, 23, 16, U_ZERO_ERROR },
1223 { "fr123", "en", FALSE, ustr_fr123, 0, 0, 0, U_PARSE_ERROR },
1224 { "ja123", "ja", FALSE, ustr_ja123, 0, 123, 4, U_ZERO_ERROR },
1225 { "ja123", "ja", FALSE, ustr_ja123, 1, 23, 4, U_ZERO_ERROR },
1226 { "ja123", "fr", FALSE, ustr_ja123, 0, 0, 0, U_PARSE_ERROR },
1227 { "zh,50s", "zh", FALSE, ustr_zh50s, 0, 50, 2, U_ZERO_ERROR },
1228 // from ICU50m2, NUMERIC_STRINGS_NOT_PARSEABLE no longer affects the next three
1229 { "zh@hd,50d", "zh@numbers=hanidec", FALSE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR },
1230 { "zh@hd,05a", "zh@numbers=hanidec", FALSE, ustr_zh05a, 0, 5, 2, U_ZERO_ERROR },
1231 { "zh@hd,05d", "zh@numbers=hanidec", FALSE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR },
1232 { "zh@hd,50dL","zh@numbers=hanidec", TRUE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR },
1233 { "zh@hd,05aL","zh@numbers=hanidec", TRUE, ustr_zh05a, 0, 5, 2, U_ZERO_ERROR },
1234 { "zh@hd,05dL","zh@numbers=hanidec", TRUE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR },
1235 { "zh,50dL","zh", TRUE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
1236 { "zh,05aL","zh", TRUE, ustr_zh05a, 0, 0, 1, U_ZERO_ERROR },
1237 { "zh,05dL","zh", TRUE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
1238 { NULL, NULL, FALSE, NULL, 0, 0, 0, 0 } /* terminator */
1239 };
1240
1241 static void TestSpelloutNumberParse()
1242 {
1243 const NumParseTestItem * testPtr;
1244 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
1245 UErrorCode status = U_ZERO_ERROR;
1246 int32_t value, position = testPtr->startPos;
1247 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
1248 if (U_FAILURE(status)) {
1249 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1250 continue;
1251 }
1252 unum_setAttribute(nf, UNUM_LENIENT_PARSE, testPtr->lenient);
1253 status = U_ZERO_ERROR;
1254 value = unum_parse(nf, testPtr->source, -1, &position, &status);
1255 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1256 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1257 testPtr->locale, testPtr->testname, testPtr->startPos,
1258 testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1259 value, position, myErrorName(status) );
1260 }
1261 unum_close(nf);
1262 }
1263 }
1264
1265 static void TestSignificantDigits()
1266 {
1267 UChar temp[128];
1268 int32_t resultlengthneeded;
1269 int32_t resultlength;
1270 UErrorCode status = U_ZERO_ERROR;
1271 UChar *result = NULL;
1272 UNumberFormat* fmt;
1273 double d = 123456.789;
1274
1275 u_uastrcpy(temp, "###0.0#");
1276 fmt=unum_open(UNUM_IGNORE, temp, -1, "en", NULL, &status);
1277 if (U_FAILURE(status)) {
1278 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1279 return;
1280 }
1281 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1282 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6);
1283
1284 u_uastrcpy(temp, "123457");
1285 resultlength=0;
1286 resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status);
1287 if(status==U_BUFFER_OVERFLOW_ERROR)
1288 {
1289 status=U_ZERO_ERROR;
1290 resultlength=resultlengthneeded+1;
1291 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1292 unum_formatDouble(fmt, d, result, resultlength, NULL, &status);
1293 }
1294 if(U_FAILURE(status))
1295 {
1296 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1297 return;
1298 }
1299 if(u_strcmp(result, temp)==0)
1300 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1301 else
1302 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1303 free(result);
1304 unum_close(fmt);
1305 }
1306
1307 static void TestSigDigRounding()
1308 {
1309 UErrorCode status = U_ZERO_ERROR;
1310 UChar expected[128];
1311 UChar result[128];
1312 char temp1[128];
1313 char temp2[128];
1314 UNumberFormat* fmt;
1315 double d = 123.4;
1316
1317 fmt=unum_open(UNUM_DECIMAL, NULL, 0, "en", NULL, &status);
1318 if (U_FAILURE(status)) {
1319 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1320 return;
1321 }
1322 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE);
1323 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1324 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2);
1325 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1326
1327 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP);
1328 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0);
1329
1330 (void)unum_formatDouble(fmt, d, result, UPRV_LENGTHOF(result), NULL, &status);
1331 if(U_FAILURE(status))
1332 {
1333 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1334 return;
1335 }
1336
1337 u_uastrcpy(expected, "140");
1338 if(u_strcmp(result, expected)!=0)
1339 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) );
1340
1341 unum_close(fmt);
1342 }
1343
1344 static void TestNumberFormatPadding()
1345 {
1346 UChar *result=NULL;
1347 UChar temp1[512];
1348 UChar temp2[512];
1349
1350 UErrorCode status=U_ZERO_ERROR;
1351 int32_t resultlength;
1352 int32_t resultlengthneeded;
1353 UNumberFormat *pattern;
1354 double d1;
1355 double d = -10456.37;
1356 UFieldPosition pos1;
1357 int32_t parsepos;
1358
1359 /* create a number format using unum_openPattern(....)*/
1360 log_verbose("\nTesting unum_openPattern() with padding\n");
1361 u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)");
1362 status=U_ZERO_ERROR;
1363 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
1364 if(U_SUCCESS(status))
1365 {
1366 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
1367 }
1368 else
1369 {
1370 unum_close(pattern);
1371 }
1372
1373 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1374 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
1375 u_uastrcpy(temp2, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // output pattern, ICU 61 behavior
1376 status=U_ZERO_ERROR;
1377 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
1378 if(U_FAILURE(status))
1379 {
1380 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
1381 }
1382 else {
1383 log_verbose("Pass: padding unum_openPattern() works fine\n");
1384
1385 /*test for unum_toPattern()*/
1386 log_verbose("\nTesting padding unum_toPattern()\n");
1387 resultlength=0;
1388 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
1389 if(status==U_BUFFER_OVERFLOW_ERROR)
1390 {
1391 status=U_ZERO_ERROR;
1392 resultlength=resultlengthneeded+1;
1393 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1394 unum_toPattern(pattern, FALSE, result, resultlength, &status);
1395 }
1396 if(U_FAILURE(status))
1397 {
1398 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status));
1399 }
1400 else
1401 {
1402 if(u_strncmp(result, temp2, resultlengthneeded)!=0) {
1403 log_err(
1404 "FAIL: Error in extracting the padding pattern using unum_toPattern(): %d: %s != %s\n",
1405 resultlengthneeded,
1406 austrdup(temp2),
1407 austrdup(result));
1408 } else {
1409 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1410 }
1411 }
1412 free(result);
1413 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1414 u_uastrcpy(temp1, "xxxxx(10,456.37)");
1415 resultlength=0;
1416 pos1.field = UNUM_FRACTION_FIELD;
1417 resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status);
1418 if(status==U_BUFFER_OVERFLOW_ERROR)
1419 {
1420 status=U_ZERO_ERROR;
1421 resultlength=resultlengthneeded+1;
1422 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1423 unum_formatDouble(pattern, d, result, resultlength, NULL, &status);
1424 }
1425 if(U_FAILURE(status))
1426 {
1427 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status));
1428 }
1429 else
1430 {
1431 if(u_strcmp(result, temp1)==0)
1432 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1433 else
1434 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1435 if(pos1.beginIndex == 13 && pos1.endIndex == 15)
1436 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1437 else
1438 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1439 pos1.beginIndex, pos1.endIndex);
1440
1441
1442 /* Testing unum_parse() and unum_parseDouble() */
1443 log_verbose("\nTesting padding unum_parseDouble()\n");
1444 parsepos=0;
1445 d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status);
1446 if(U_FAILURE(status))
1447 {
1448 log_err("padding parse failed. The error is : %s\n", myErrorName(status));
1449 }
1450
1451 if(d1!=d)
1452 log_err("Fail: Error in padding parsing\n");
1453 else
1454 log_verbose("Pass: padding parsing successful\n");
1455 free(result);
1456 }
1457 }
1458
1459 unum_close(pattern);
1460 }
1461
1462 static UBool
1463 withinErr(double a, double b, double err) {
1464 return uprv_fabs(a - b) < uprv_fabs(a * err);
1465 }
1466
1467 static void TestInt64Format() {
1468 UChar temp1[512];
1469 UChar result[512];
1470 UNumberFormat *fmt;
1471 UErrorCode status = U_ZERO_ERROR;
1472 const double doubleInt64Max = (double)U_INT64_MAX;
1473 const double doubleInt64Min = (double)U_INT64_MIN;
1474 const double doubleBig = 10.0 * (double)U_INT64_MAX;
1475 int32_t val32;
1476 int64_t val64;
1477 double valDouble;
1478 int32_t parsepos;
1479
1480 /* create a number format using unum_openPattern(....) */
1481 log_verbose("\nTesting Int64Format\n");
1482 u_uastrcpy(temp1, "#.#E0");
1483 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), "en_US", NULL, &status);
1484 if(U_FAILURE(status)) {
1485 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
1486 } else {
1487 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20);
1488 unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status);
1489 if (U_FAILURE(status)) {
1490 log_err("error in unum_format(): %s\n", myErrorName(status));
1491 } else {
1492 log_verbose("format int64max: '%s'\n", result);
1493 parsepos = 0;
1494 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1495 if (status != U_INVALID_FORMAT_ERROR) {
1496 log_err("parse didn't report error: %s\n", myErrorName(status));
1497 } else if (val32 != INT32_MAX) {
1498 log_err("parse didn't pin return value, got: %d\n", val32);
1499 }
1500
1501 status = U_ZERO_ERROR;
1502 parsepos = 0;
1503 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1504 if (U_FAILURE(status)) {
1505 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1506 } else if (val64 != U_INT64_MAX) {
1507 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1508 }
1509
1510 status = U_ZERO_ERROR;
1511 parsepos = 0;
1512 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1513 if (U_FAILURE(status)) {
1514 log_err("parseDouble returned error: %s\n", myErrorName(status));
1515 } else if (valDouble != doubleInt64Max) {
1516 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1517 }
1518 }
1519
1520 unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status);
1521 if (U_FAILURE(status)) {
1522 log_err("error in unum_format(): %s\n", myErrorName(status));
1523 } else {
1524 log_verbose("format int64min: '%s'\n", result);
1525 parsepos = 0;
1526 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1527 if (status != U_INVALID_FORMAT_ERROR) {
1528 log_err("parse didn't report error: %s\n", myErrorName(status));
1529 } else if (val32 != INT32_MIN) {
1530 log_err("parse didn't pin return value, got: %d\n", val32);
1531 }
1532
1533 status = U_ZERO_ERROR;
1534 parsepos = 0;
1535 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1536 if (U_FAILURE(status)) {
1537 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1538 } else if (val64 != U_INT64_MIN) {
1539 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1540 }
1541
1542 status = U_ZERO_ERROR;
1543 parsepos = 0;
1544 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1545 if (U_FAILURE(status)) {
1546 log_err("parseDouble returned error: %s\n", myErrorName(status));
1547 } else if (valDouble != doubleInt64Min) {
1548 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1549 }
1550 }
1551
1552 unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status);
1553 if (U_FAILURE(status)) {
1554 log_err("error in unum_format(): %s\n", myErrorName(status));
1555 } else {
1556 log_verbose("format doubleBig: '%s'\n", result);
1557 parsepos = 0;
1558 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1559 if (status != U_INVALID_FORMAT_ERROR) {
1560 log_err("parse didn't report error: %s\n", myErrorName(status));
1561 } else if (val32 != INT32_MAX) {
1562 log_err("parse didn't pin return value, got: %d\n", val32);
1563 }
1564
1565 status = U_ZERO_ERROR;
1566 parsepos = 0;
1567 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1568 if (status != U_INVALID_FORMAT_ERROR) {
1569 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status));
1570 } else if (val64 != U_INT64_MAX) {
1571 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1572 }
1573
1574 status = U_ZERO_ERROR;
1575 parsepos = 0;
1576 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1577 if (U_FAILURE(status)) {
1578 log_err("parseDouble returned error: %s\n", myErrorName(status));
1579 } else if (!withinErr(valDouble, doubleBig, 1e-15)) {
1580 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1581 }
1582 }
1583
1584 u_uastrcpy(result, "5.06e-27");
1585 parsepos = 0;
1586 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1587 if (U_FAILURE(status)) {
1588 log_err("parseDouble() returned error: %s\n", myErrorName(status));
1589 } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) {
1590 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble);
1591 }
1592 }
1593 unum_close(fmt);
1594 }
1595
1596
1597 static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
1598 char temp[512];
1599 UChar buffer[512];
1600 int32_t BUFSIZE = UPRV_LENGTHOF(buffer);
1601 double vals[] = {
1602 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1603 };
1604 int i;
1605
1606 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
1607 UErrorCode status = U_ZERO_ERROR;
1608 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1609 if (U_FAILURE(status)) {
1610 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1611 } else {
1612 u_austrcpy(temp, buffer);
1613 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1614 }
1615 }
1616
1617 /* check APIs now */
1618 {
1619 UErrorCode status = U_ZERO_ERROR;
1620 UParseError perr;
1621 u_uastrcpy(buffer, "#,##0.0#");
1622 unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status);
1623 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1624 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status));
1625 }
1626 }
1627
1628 {
1629 int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1630 log_verbose("lenient: 0x%x\n", isLenient);
1631 if (isLenient != FALSE) {
1632 log_err("didn't expect lenient value: %d\n", isLenient);
1633 }
1634
1635 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE);
1636 isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1637 if (isLenient != TRUE) {
1638 log_err("didn't expect lenient value after set: %d\n", isLenient);
1639 }
1640 }
1641
1642 {
1643 double val2;
1644 double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE);
1645 if (val != -1) {
1646 log_err("didn't expect double attribute\n");
1647 }
1648 val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1649 if ((val == -1) == isDecimal) {
1650 log_err("didn't expect -1 rounding increment\n");
1651 }
1652 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5);
1653 val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1654 if (isDecimal && (val2 - val != .5)) {
1655 log_err("set rounding increment had no effect on decimal format");
1656 }
1657 }
1658
1659 {
1660 UErrorCode status = U_ZERO_ERROR;
1661 int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1662 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1663 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status));
1664 }
1665 if (U_SUCCESS(status)) {
1666 u_austrcpy(temp, buffer);
1667 log_verbose("default ruleset: '%s'\n", temp);
1668 }
1669
1670 status = U_ZERO_ERROR;
1671 len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status);
1672 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1673 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status));
1674 }
1675 if (U_SUCCESS(status)) {
1676 u_austrcpy(temp, buffer);
1677 log_verbose("public rulesets: '%s'\n", temp);
1678
1679 /* set the default ruleset to the first one found, and retry */
1680
1681 if (len > 0) {
1682 for (i = 0; i < len && temp[i] != ';'; ++i){};
1683 if (i < len) {
1684 buffer[i] = 0;
1685 unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status);
1686 if (U_FAILURE(status)) {
1687 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status));
1688 } else {
1689 int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1690 if (U_FAILURE(status)) {
1691 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status));
1692 } else if (len2 != i) {
1693 u_austrcpy(temp, buffer);
1694 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp);
1695 } else {
1696 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
1697 status = U_ZERO_ERROR;
1698 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1699 if (U_FAILURE(status)) {
1700 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1701 } else {
1702 u_austrcpy(temp, buffer);
1703 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1704 }
1705 }
1706 }
1707 }
1708 }
1709 }
1710 }
1711 }
1712
1713 {
1714 UErrorCode status = U_ZERO_ERROR;
1715 unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status);
1716 if (U_SUCCESS(status)) {
1717 u_austrcpy(temp, buffer);
1718 log_verbose("pattern: '%s'\n", temp);
1719 } else if (status != U_BUFFER_OVERFLOW_ERROR) {
1720 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status));
1721 } else {
1722 log_verbose("pattern too long to display\n");
1723 }
1724 }
1725
1726 {
1727 UErrorCode status = U_ZERO_ERROR;
1728 int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status);
1729 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1730 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status));
1731 }
1732
1733 unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status);
1734 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1735 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status));
1736 }
1737 }
1738 }
1739
1740 static void TestNonExistentCurrency() {
1741 UNumberFormat *format;
1742 UErrorCode status = U_ZERO_ERROR;
1743 UChar currencySymbol[8];
1744 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
1745
1746 /* Get a non-existent currency and make sure it returns the correct currency code. */
1747 format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status);
1748 if (format == NULL || U_FAILURE(status)) {
1749 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status));
1750 }
1751 else {
1752 unum_getSymbol(format,
1753 UNUM_CURRENCY_SYMBOL,
1754 currencySymbol,
1755 UPRV_LENGTHOF(currencySymbol),
1756 &status);
1757 if (u_strcmp(currencySymbol, QQQ) != 0) {
1758 log_err("unum_open set the currency to QQQ\n");
1759 }
1760 }
1761 unum_close(format);
1762 }
1763
1764 static void TestRBNFFormat() {
1765 UErrorCode status;
1766 UParseError perr;
1767 UChar pat[1024];
1768 UChar tempUChars[512];
1769 UNumberFormat *formats[5];
1770 int COUNT = UPRV_LENGTHOF(formats);
1771 int i;
1772
1773 for (i = 0; i < COUNT; ++i) {
1774 formats[i] = 0;
1775 }
1776
1777 /* instantiation */
1778 status = U_ZERO_ERROR;
1779 u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)");
1780 formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status);
1781 if (U_FAILURE(status)) {
1782 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
1783 return;
1784 }
1785
1786 status = U_ZERO_ERROR;
1787 formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status);
1788 if (U_FAILURE(status)) {
1789 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1790 return;
1791 }
1792
1793 status = U_ZERO_ERROR;
1794 formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status);
1795 if (U_FAILURE(status)) {
1796 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
1797 return;
1798 }
1799
1800 status = U_ZERO_ERROR;
1801 formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status);
1802 if (U_FAILURE(status)) {
1803 log_err_status(status, "unable to open duration %s\n", u_errorName(status));
1804 return;
1805 }
1806
1807 status = U_ZERO_ERROR;
1808 u_uastrcpy(pat,
1809 "%standard:\n"
1810 "-x: minus >>;\n"
1811 "x.x: << point >>;\n"
1812 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1813 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1814 "seventeen; eighteen; nineteen;\n"
1815 "20: twenty[->>];\n"
1816 "30: thirty[->>];\n"
1817 "40: forty[->>];\n"
1818 "50: fifty[->>];\n"
1819 "60: sixty[->>];\n"
1820 "70: seventy[->>];\n"
1821 "80: eighty[->>];\n"
1822 "90: ninety[->>];\n"
1823 "100: =#,##0=;\n");
1824 u_uastrcpy(tempUChars,
1825 "%simple:\n"
1826 "=%standard=;\n"
1827 "20: twenty[ and change];\n"
1828 "30: thirty[ and change];\n"
1829 "40: forty[ and change];\n"
1830 "50: fifty[ and change];\n"
1831 "60: sixty[ and change];\n"
1832 "70: seventy[ and change];\n"
1833 "80: eighty[ and change];\n"
1834 "90: ninety[ and change];\n"
1835 "100: =#,##0=;\n"
1836 "%bogus:\n"
1837 "0.x: tiny;\n"
1838 "x.x: << point something;\n"
1839 "=%standard=;\n"
1840 "20: some reasonable number;\n"
1841 "100: some substantial number;\n"
1842 "100,000,000: some huge number;\n");
1843 /* This is to get around some compiler warnings about char * string length. */
1844 u_strcat(pat, tempUChars);
1845 formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status);
1846 if (U_FAILURE(status)) {
1847 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
1848 }
1849 if (U_FAILURE(status)) {
1850 log_err_status(status, "Something failed with %s\n", u_errorName(status));
1851 return;
1852 }
1853
1854 for (i = 0; i < COUNT; ++i) {
1855 log_verbose("\n\ntesting format %d\n", i);
1856 test_fmt(formats[i], (UBool)(i == 0));
1857 }
1858
1859 #define FORMAT_BUF_CAPACITY 64
1860 {
1861 UChar fmtbuf[FORMAT_BUF_CAPACITY];
1862 int32_t len;
1863 double nanvalue = uprv_getNaN();
1864 status = U_ZERO_ERROR;
1865 len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1866 if (U_FAILURE(status)) {
1867 log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status));
1868 } else {
1869 UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1870 if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) {
1871 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1872 }
1873 }
1874 }
1875
1876 for (i = 0; i < COUNT; ++i) {
1877 unum_close(formats[i]);
1878 }
1879 }
1880
1881 static void TestRBNFRounding() {
1882 UChar fmtbuf[FORMAT_BUF_CAPACITY];
1883 UChar expectedBuf[FORMAT_BUF_CAPACITY];
1884 int32_t len;
1885 UErrorCode status = U_ZERO_ERROR;
1886 UNumberFormat* fmt = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", NULL, &status);
1887 if (U_FAILURE(status)) {
1888 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1889 return;
1890 }
1891 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1892 if (U_FAILURE(status)) {
1893 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
1894 }
1895 u_uastrcpy(expectedBuf, "ten point one two three four five six seven eight nine");
1896 if (u_strcmp(expectedBuf, fmtbuf) != 0) {
1897 log_err("Wrong result for unrounded value\n");
1898 }
1899 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 3);
1900 if (unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS) != 3) {
1901 log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS));
1902 }
1903 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_UNNECESSARY) {
1904 log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
1905 }
1906 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP);
1907 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_HALFUP) {
1908 log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
1909 }
1910 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1911 if (U_FAILURE(status)) {
1912 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
1913 }
1914 u_uastrcpy(expectedBuf, "ten point one two three");
1915 if (u_strcmp(expectedBuf, fmtbuf) != 0) {
1916 char temp[512];
1917 u_austrcpy(temp, fmtbuf);
1918 log_err("Wrong result for rounded value. Got: %s\n", temp);
1919 }
1920 unum_close(fmt);
1921 }
1922
1923 static void TestCurrencyRegression(void) {
1924 /*
1925 I've found a case where unum_parseDoubleCurrency is not doing what I
1926 expect. The value I pass in is $1234567890q123460000.00 and this
1927 returns with a status of zero error & a parse pos of 22 (I would
1928 expect a parse error at position 11).
1929
1930 I stepped into DecimalFormat::subparse() and it looks like it parses
1931 the first 10 digits and then stops parsing at the q but doesn't set an
1932 error. Then later in DecimalFormat::parse() the value gets crammed
1933 into a long (which greatly truncates the value).
1934
1935 This is very problematic for me 'cause I try to remove chars that are
1936 invalid but this allows my users to enter bad chars and truncates
1937 their data!
1938 */
1939
1940 UChar buf[1024];
1941 UChar currency[8];
1942 char acurrency[16];
1943 double d;
1944 UNumberFormat *cur;
1945 int32_t pos;
1946 UErrorCode status = U_ZERO_ERROR;
1947 const int32_t expected = 11;
1948
1949 currency[0]=0;
1950 u_uastrcpy(buf, "$1234567890q643210000.00");
1951 cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status);
1952
1953 if(U_FAILURE(status)) {
1954 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
1955 return;
1956 }
1957
1958 status = U_ZERO_ERROR; /* so we can test it later. */
1959 pos = 0;
1960
1961 d = unum_parseDoubleCurrency(cur,
1962 buf,
1963 -1,
1964 &pos, /* 0 = start */
1965 currency,
1966 &status);
1967
1968 u_austrcpy(acurrency, currency);
1969
1970 if(U_FAILURE(status) || (pos != expected)) {
1971 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
1972 expected, d, u_errorName(status), pos, acurrency);
1973 } else {
1974 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency);
1975 }
1976
1977 unum_close(cur);
1978 }
1979
1980 static void TestTextAttributeCrash(void) {
1981 UChar ubuffer[64] = {0x0049,0x004E,0x0052,0};
1982 static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1983 static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
1984 int32_t used;
1985 UErrorCode status = U_ZERO_ERROR;
1986 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
1987 if (U_FAILURE(status)) {
1988 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
1989 return;
1990 }
1991 unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status);
1992 /*
1993 * the usual negative prefix and suffix seem to be '($' and ')' at this point
1994 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
1995 */
1996 used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status);
1997 unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status);
1998 if (U_FAILURE(status)) {
1999 log_err("FAILED 2\n"); exit(1);
2000 }
2001 log_verbose("attempting to format...\n");
2002 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
2003 if (U_FAILURE(status) || 64 < used) {
2004 log_err("Failed formatting %s\n", u_errorName(status));
2005 return;
2006 }
2007 if (u_strcmp(expectedNeg, ubuffer) == 0) {
2008 log_err("Didn't get expected negative result\n");
2009 }
2010 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
2011 if (U_FAILURE(status) || 64 < used) {
2012 log_err("Failed formatting %s\n", u_errorName(status));
2013 return;
2014 }
2015 if (u_strcmp(expectedPos, ubuffer) == 0) {
2016 log_err("Didn't get expected positive result\n");
2017 }
2018 unum_close(nf);
2019 }
2020
2021 static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
2022 UErrorCode status = U_ZERO_ERROR;
2023 UChar myString[20];
2024 char tmpbuf[200];
2025 double aNumber = -1.0;
2026 unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
2027 log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
2028 if(U_FAILURE(status)) {
2029 log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
2030 return;
2031 }
2032 aNumber = unum_parse(nf, myString, -1, NULL, &status);
2033 if(U_FAILURE(status)) {
2034 log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
2035 return;
2036 }
2037 if(uprv_fabs(aNumber-myNumber)>.001) {
2038 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
2039 } else {
2040 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
2041 }
2042 }
2043
2044 static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
2045 TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
2046 TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
2047 }
2048
2049 static void TestNBSPInPattern(void) {
2050 UErrorCode status = U_ZERO_ERROR;
2051 UNumberFormat* nf = NULL;
2052 const char *testcase;
2053
2054
2055 testcase="ar_AE UNUM_CURRENCY";
2056 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
2057 if(U_FAILURE(status) || nf == NULL) {
2058 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
2059 return;
2060 }
2061 TestNBSPPatternRT(testcase, nf);
2062
2063 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
2064 {
2065 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
2066 UChar pat[200];
2067 testcase = "ar_AE special pattern: " SPECIAL_PATTERN;
2068 u_unescape(SPECIAL_PATTERN, pat, UPRV_LENGTHOF(pat));
2069 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
2070 if(U_FAILURE(status)) {
2071 log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status));
2072 } else {
2073 TestNBSPPatternRT(testcase, nf);
2074 }
2075 #undef SPECIAL_PATTERN
2076 }
2077 unum_close(nf); status = U_ZERO_ERROR;
2078
2079 testcase="ar_AE UNUM_DECIMAL";
2080 nf = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status);
2081 if(U_FAILURE(status)) {
2082 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
2083 }
2084 TestNBSPPatternRT(testcase, nf);
2085 unum_close(nf); status = U_ZERO_ERROR;
2086
2087 testcase="ar_AE UNUM_PERCENT";
2088 nf = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status);
2089 if(U_FAILURE(status)) {
2090 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
2091 }
2092 TestNBSPPatternRT(testcase, nf);
2093 unum_close(nf); status = U_ZERO_ERROR;
2094
2095
2096
2097 }
2098 static void TestCloneWithRBNF(void) {
2099 UChar pattern[1024];
2100 UChar pat2[512];
2101 UErrorCode status = U_ZERO_ERROR;
2102 UChar buffer[256];
2103 UChar buffer_cloned[256];
2104 char temp1[256];
2105 char temp2[256];
2106 UNumberFormat *pform_cloned;
2107 UNumberFormat *pform;
2108
2109 u_uastrcpy(pattern,
2110 "%main:\n"
2111 "0.x: >%%millis-only>;\n"
2112 "x.0: <%%duration<;\n"
2113 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2114 "-x: ->>;%%millis-only:\n"
2115 "1000: 00:00.<%%millis<;\n"
2116 "%%millis-added:\n"
2117 "1000: .<%%millis<;\n"
2118 "%%millis:\n"
2119 "0: =000=;\n"
2120 "%%duration:\n"
2121 "0: =%%seconds-only=;\n"
2122 "60: =%%min-sec=;\n"
2123 "3600: =%%hr-min-sec=;\n"
2124 "86400/86400: <%%ddaayyss<[, >>];\n"
2125 "%%durationwithmillis:\n"
2126 "0: =%%seconds-only=;\n"
2127 "60: =%%min-sec=;\n"
2128 "3600: =%%hr-min-sec=;\n"
2129 "86400/86400: <%%ddaayyss<, >>;\n");
2130 u_uastrcpy(pat2,
2131 "%%seconds-only:\n"
2132 "0: 0:00:=00=;\n"
2133 "%%min-sec:\n"
2134 "0: :=00=;\n"
2135 "0/60: 0:<00<>>;\n"
2136 "%%hr-min-sec:\n"
2137 "0: :=00=;\n"
2138 "60/60: <00<>>;\n"
2139 "3600/60: <0<:>>>;\n"
2140 "%%ddaayyss:\n"
2141 "0 days;\n"
2142 "1 day;\n"
2143 "=0= days;");
2144
2145 /* This is to get around some compiler warnings about char * string length. */
2146 u_strcat(pattern, pat2);
2147
2148 pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status);
2149 unum_formatDouble(pform, 3600, buffer, 256, NULL, &status);
2150
2151 pform_cloned = unum_clone(pform,&status);
2152 unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status);
2153
2154 unum_close(pform);
2155 unum_close(pform_cloned);
2156
2157 if (u_strcmp(buffer,buffer_cloned)) {
2158 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));
2159 }
2160 }
2161
2162
2163 static void TestNoExponent(void) {
2164 UErrorCode status = U_ZERO_ERROR;
2165 UChar str[100];
2166 const char *cstr;
2167 UNumberFormat *fmt;
2168 int32_t pos;
2169 int32_t expect = 0;
2170 int32_t num;
2171
2172 fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status);
2173
2174 if(U_FAILURE(status) || fmt == NULL) {
2175 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status));
2176 return;
2177 }
2178
2179 cstr = "10E6";
2180 u_uastrcpy(str, cstr);
2181 expect = 10000000;
2182 pos = 0;
2183 num = unum_parse(fmt, str, -1, &pos, &status);
2184 ASSERT_TRUE(pos==4);
2185 if(U_FAILURE(status)) {
2186 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2187 } else if(expect!=num) {
2188 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2189 } else {
2190 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2191 }
2192
2193 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2194
2195 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2196 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2197
2198 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2199
2200 pos = 0;
2201 expect=10;
2202 num = unum_parse(fmt, str, -1, &pos, &status);
2203 if(num==10000000) {
2204 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr);
2205 } else if(num==expect) {
2206 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr);
2207 }
2208 ASSERT_TRUE(pos==2);
2209
2210 status = U_ZERO_ERROR;
2211
2212 unum_close(fmt);
2213
2214 /* ok, now try scientific */
2215 fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status);
2216 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status);
2217
2218 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2219
2220 cstr = "10E6";
2221 u_uastrcpy(str, cstr);
2222 expect = 10000000;
2223 pos = 0;
2224 num = unum_parse(fmt, str, -1, &pos, &status);
2225 ASSERT_TRUE(pos==4);
2226 if(U_FAILURE(status)) {
2227 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2228 } else if(expect!=num) {
2229 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2230 } else {
2231 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2232 }
2233
2234 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2235 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2236
2237 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2238
2239 // A scientific formatter should parse the exponent even if UNUM_PARSE_NO_EXPONENT is set
2240 cstr = "10E6";
2241 u_uastrcpy(str, cstr);
2242 expect = 10000000;
2243 pos = 0;
2244 num = unum_parse(fmt, str, -1, &pos, &status);
2245 ASSERT_TRUE(pos==4);
2246 if(U_FAILURE(status)) {
2247 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2248 } else if(expect!=num) {
2249 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2250 } else {
2251 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2252 }
2253
2254 unum_close(fmt);
2255 }
2256
2257 static void TestMaxInt(void) {
2258 UErrorCode status = U_ZERO_ERROR;
2259 UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */
2260 UChar result1[1024] = { 0 }, result2[1024] = { 0 };
2261 int32_t len1, len2;
2262 UChar expect[] = { 0x0039, 0x0037, 0 };
2263 UNumberFormat *fmt = unum_open(
2264 UNUM_PATTERN_DECIMAL, /* style */
2265 &pattern_hash[0], /* pattern */
2266 u_strlen(pattern_hash), /* patternLength */
2267 "en",
2268 0, /* parseErr */
2269 &status);
2270 if(U_FAILURE(status) || fmt == NULL) {
2271 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status));
2272 return;
2273 }
2274
2275 unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2);
2276
2277 status = U_ZERO_ERROR;
2278 /* #1 */
2279 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2280 result1[len1]=0;
2281 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2282 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2283 }
2284
2285 status = U_ZERO_ERROR;
2286 /* #2 */
2287 len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status);
2288 result2[len2]=0;
2289 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2290 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2291 }
2292
2293
2294
2295 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2296 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0);
2297
2298 unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1);
2299 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2300 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1);
2301
2302 status = U_ZERO_ERROR;
2303 /* max int digits still '2' */
2304 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2305 ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR);
2306 status = U_ZERO_ERROR;
2307
2308 /* But, formatting 97->'97' works fine. */
2309
2310 /* #1 */
2311 len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status);
2312 result1[len1]=0;
2313 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2314 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2315 }
2316
2317 status = U_ZERO_ERROR;
2318 /* #2 */
2319 len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status);
2320 result2[len2]=0;
2321 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2322 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2323 }
2324
2325
2326 unum_close(fmt);
2327 }
2328
2329 static void TestUFormattable(void) {
2330 UChar out2k[2048];
2331 // simple test for API docs
2332 {
2333 UErrorCode status = U_ZERO_ERROR;
2334 UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2335 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2336 //! [unum_parseToUFormattable]
2337 const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2338 int32_t result = 0;
2339 UFormattable *ufmt = ufmt_open(&status);
2340 unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status);
2341 if (ufmt_isNumeric(ufmt)) {
2342 result = ufmt_getLong(ufmt, &status); /* == 123 */
2343 } /* else { ... } */
2344 ufmt_close(ufmt);
2345 //! [unum_parseToUFormattable]
2346 assertTrue("result == 123", (result == 123));
2347 }
2348 unum_close(unum);
2349 }
2350 // test with explicitly created ufmt_open
2351 {
2352 UChar buffer[2048];
2353 UErrorCode status = U_ZERO_ERROR;
2354 UFormattable *ufmt;
2355 UNumberFormat *unum;
2356 const char *pattern = "";
2357
2358 ufmt = ufmt_open(&status);
2359 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2360 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) {
2361
2362 pattern = "31337";
2363 log_verbose("-- pattern: %s\n", pattern);
2364 u_uastrcpy(buffer, pattern);
2365 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2366 if(assertSuccess("unum_parseToUFormattable(31337)", &status)) {
2367 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337);
2368 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG);
2369 log_verbose("long = %d\n", ufmt_getLong(ufmt, &status));
2370 assertSuccess("ufmt_getLong()", &status);
2371 }
2372 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2373 if(assertSuccess("unum_formatUFormattable(31337)", &status)) {
2374 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2375 }
2376
2377 pattern = "3.14159";
2378 log_verbose("-- pattern: %s\n", pattern);
2379 u_uastrcpy(buffer, pattern);
2380 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2381 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) {
2382 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15));
2383 assertSuccess("ufmt_getDouble()", &status);
2384 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE);
2385 log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status));
2386 }
2387 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2388 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2389 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2390 }
2391 }
2392 ufmt_close(ufmt);
2393 unum_close(unum);
2394 }
2395
2396 // test with auto-generated ufmt
2397 {
2398 UChar buffer[2048];
2399 UErrorCode status = U_ZERO_ERROR;
2400 UFormattable *ufmt = NULL;
2401 UNumberFormat *unum;
2402 const char *pattern = "73476730924573500000000"; // weight of the moon, kg
2403
2404 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern);
2405 u_uastrcpy(buffer, pattern);
2406
2407 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2408 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2409
2410 ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */
2411 buffer, -1, NULL, &status);
2412 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) {
2413 log_verbose("new formattable allocated at %p\n", (void*)ufmt);
2414 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt));
2415 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2416 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2417 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2418 }
2419
2420 log_verbose("double: %g\n", ufmt_getDouble(ufmt, &status));
2421 assertSuccess("ufmt_getDouble()", &status);
2422
2423 log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status));
2424 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status));
2425 // status is now a failure due to ufmt_getLong() above.
2426 // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2427 }
2428 }
2429
2430 unum_close(unum);
2431 ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable()
2432 }
2433 }
2434
2435 typedef struct {
2436 const char* locale;
2437 const char* numsys;
2438 int32_t radix;
2439 UBool isAlgorithmic;
2440 const UChar* description;
2441 } NumSysTestItem;
2442
2443
2444 static const UChar latnDesc[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2445 static const UChar romanDesc[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2446 static const UChar arabDesc[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2447 static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2448 static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2449 static const UChar hantDesc[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2450 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2451 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2452
2453 static const NumSysTestItem numSysTestItems[] = {
2454 //locale numsys radix isAlgo description
2455 { "en", "latn", 10, FALSE, latnDesc },
2456 { "en@numbers=roman", "roman", 10, TRUE, romanDesc },
2457 { "en@numbers=finance", "latn", 10, FALSE, latnDesc },
2458 { "ar-EG", "arab", 10, FALSE, arabDesc },
2459 { "fa", "arabext", 10, FALSE, arabextDesc },
2460 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE, hanidecDesc },
2461 { "zh_Hant@numbers=traditional", "hant", 10, TRUE, hantDesc },
2462 { NULL, NULL, 0, FALSE, NULL },
2463 };
2464 enum { kNumSysDescripBufMax = 64 };
2465
2466 static void TestUNumberingSystem(void) {
2467 const NumSysTestItem * itemPtr;
2468 UNumberingSystem * unumsys;
2469 UEnumeration * uenum;
2470 const char * numsys;
2471 UErrorCode status;
2472
2473 for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) {
2474 status = U_ZERO_ERROR;
2475 unumsys = unumsys_open(itemPtr->locale, &status);
2476 if ( U_SUCCESS(status) ) {
2477 UChar ubuf[kNumSysDescripBufMax];
2478 int32_t ulen, radix = unumsys_getRadix(unumsys);
2479 UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys);
2480 numsys = unumsys_getName(unumsys);
2481 if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) {
2482 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2483 itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic);
2484 }
2485 ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status);
2486 (void)ulen; // Suppress variable not used warning.
2487 if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) {
2488 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status));
2489 }
2490 unumsys_close(unumsys);
2491 } else {
2492 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status));
2493 }
2494 }
2495
2496 status = U_ZERO_ERROR;
2497 uenum = unumsys_openAvailableNames(&status);
2498 if ( U_SUCCESS(status) ) {
2499 int32_t numsysCount = 0;
2500 // sanity check for a couple of number systems that must be in the enumeration
2501 UBool foundLatn = FALSE;
2502 UBool foundArab = FALSE;
2503 while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
2504 status = U_ZERO_ERROR;
2505 unumsys = unumsys_openByName(numsys, &status);
2506 if ( U_SUCCESS(status) ) {
2507 numsysCount++;
2508 if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
2509 if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
2510 unumsys_close(unumsys);
2511 } else {
2512 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2513 numsys, myErrorName(status));
2514 }
2515 }
2516 uenum_close(uenum);
2517 if ( numsysCount < 40 || !foundLatn || !foundArab ) {
2518 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2519 numsysCount, foundLatn, foundArab);
2520 }
2521 } else {
2522 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
2523 }
2524 }
2525
2526 /* plain-C version of test in numfmtst.cpp */
2527 enum { kUBufMax = 64 };
2528 static void TestCurrencyIsoPluralFormat(void) {
2529 static const char* DATA[][8] = {
2530 // the data are:
2531 // locale,
2532 // currency amount to be formatted,
2533 // currency ISO code to be formatted,
2534 // format result using CURRENCYSTYLE,
2535 // format result using CURRENCY_STANDARD,
2536 // format result using CURRENCY_ACCOUNTING,
2537 // format result using ISOCURRENCYSTYLE,
2538 // format result using PLURALCURRENCYSTYLE,
2539
2540 // locale amount ISOcode CURRENCYSTYLE CURRENCY_STANDARD CURRENCY_ACCOUNTING ISOCURRENCYSTYLE PLURALCURRENCYSTYLE
2541 {"en_US", "1", "USD", "$1.00", "$1.00", "$1.00", "USD1.00", "1.00 US dollars"},
2542 {"en_US", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
2543 {"en_US@cf=account", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
2544 {"en_US", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2545 {"en_US@cf=account", "-1234.56", "USD", "($1,234.56)", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2546 {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"},
2547 {"zh_CN", "1", "USD", "US$1.00", "US$1.00", "US$1.00", "USD1.00", "1.00\\u7F8E\\u5143"},
2548 {"zh_CN", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2549 {"zh_CN@cf=account", "-1", "USD", "(US$1.00)", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2550 {"zh_CN@cf=standard", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"},
2551 {"zh_CN", "1234.56", "USD", "US$1,234.56", "US$1,234.56", "US$1,234.56", "USD1,234.56", "1,234.56\\u7F8E\\u5143"},
2552 // {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "CHY1.00", "CHY1.00", "1.00 CHY"}, // wrong ISO code
2553 // {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, // wrong ISO code
2554 {"zh_CN", "1", "CNY", "\\u00A51.00", "\\u00A51.00", "\\u00A51.00", "CNY1.00", "1.00\\u4EBA\\u6C11\\u5E01"},
2555 {"zh_CN", "1234.56", "CNY", "\\u00A51,234.56", "\\u00A51,234.56", "\\u00A51,234.56", "CNY1,234.56", "1,234.56\\u4EBA\\u6C11\\u5E01"},
2556 {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2557 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2558 {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2559 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2560 {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2561 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2562 // test locale without currency information
2563 {"root", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2564 {"root@cf=account", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2565 // test choice format
2566 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
2567 };
2568 static const UNumberFormatStyle currencyStyles[] = {
2569 UNUM_CURRENCY,
2570 UNUM_CURRENCY_STANDARD,
2571 UNUM_CURRENCY_ACCOUNTING,
2572 UNUM_CURRENCY_ISO,
2573 UNUM_CURRENCY_PLURAL
2574 };
2575
2576 int32_t i, sIndex;
2577
2578 for (i=0; i<UPRV_LENGTHOF(DATA); ++i) {
2579 const char* localeString = DATA[i][0];
2580 double numberToBeFormat = atof(DATA[i][1]);
2581 const char* currencyISOCode = DATA[i][2];
2582 for (sIndex = 0; sIndex < UPRV_LENGTHOF(currencyStyles); ++sIndex) {
2583 UNumberFormatStyle style = currencyStyles[sIndex];
2584 UErrorCode status = U_ZERO_ERROR;
2585 UChar currencyCode[4];
2586 UChar ubufResult[kUBufMax];
2587 UChar ubufExpected[kUBufMax];
2588 int32_t ulenRes;
2589
2590 UNumberFormat* unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
2591 if (U_FAILURE(status)) {
2592 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString, (int)style, myErrorName(status));
2593 continue;
2594 }
2595 u_charsToUChars(currencyISOCode, currencyCode, 4);
2596 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
2597 if (U_FAILURE(status)) {
2598 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s\n", localeString, currencyISOCode);
2599 }
2600 ulenRes = unum_formatDouble(unumFmt, numberToBeFormat, ubufResult, kUBufMax, NULL, &status);
2601 if (U_FAILURE(status)) {
2602 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s - %s\n", localeString, currencyISOCode, myErrorName(status));
2603 } else {
2604 int32_t ulenExp = u_unescape(DATA[i][3 + sIndex], ubufExpected, kUBufMax);
2605 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
2606 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got something else\n",
2607 localeString, currencyISOCode, DATA[i][3 + sIndex]);
2608 }
2609 }
2610 unum_close(unumFmt);
2611 }
2612 }
2613 }
2614
2615 typedef struct {
2616 const char * locale;
2617 UNumberFormatStyle style;
2618 UDisplayContext context;
2619 const char * expectedResult;
2620 } TestContextItem;
2621
2622 /* currently no locales have contextTransforms data for "symbol" type */
2623 static const TestContextItem tcItems[] = { /* results for 123.45 */
2624 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2625 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2626 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2627 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2628 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "one hundred twenty-three point four five" },
2629 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "One hundred twenty-three point four five" },
2630 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "One hundred twenty-three point four five" },
2631 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "One hundred twenty-three point four five" },
2632 { NULL, (UNumberFormatStyle)0, (UDisplayContext)0, NULL }
2633 };
2634
2635 static void TestContext(void) {
2636 UErrorCode status = U_ZERO_ERROR;
2637 const TestContextItem* itemPtr;
2638
2639 UNumberFormat *unum = unum_open(UNUM_SPELLOUT, NULL, 0, "en", NULL, &status);
2640 if ( U_SUCCESS(status) ) {
2641 UDisplayContext context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
2642 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_NONE) {
2643 log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n");
2644 status = U_ZERO_ERROR;
2645 }
2646 unum_setContext(unum, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
2647 context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
2648 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
2649 log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n");
2650 }
2651 unum_close(unum);
2652 } else {
2653 log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status));
2654 }
2655 #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION
2656 for (itemPtr = tcItems; itemPtr->locale != NULL; itemPtr++) {
2657 UChar ubufResult[kUBufMax];
2658 int32_t ulenRes;
2659
2660 status = U_ZERO_ERROR;
2661 unum = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
2662 if (U_FAILURE(status)) {
2663 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2664 itemPtr->locale, (int)itemPtr->style, myErrorName(status));
2665 continue;
2666 }
2667 unum_setContext(unum, itemPtr->context, &status);
2668 ulenRes = unum_formatDouble(unum, 123.45, ubufResult, kUBufMax, NULL, &status);
2669 if (U_FAILURE(status)) {
2670 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
2671 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, myErrorName(status));
2672 } else {
2673 UChar ubufExpected[kUBufMax];
2674 int32_t ulenExp = u_unescape(itemPtr->expectedResult, ubufExpected, kUBufMax);
2675 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
2676 char bbuf[kUBufMax*2];
2677 u_austrncpy(bbuf, ubufResult, sizeof(bbuf));
2678 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
2679 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, ulenExp,
2680 itemPtr->expectedResult, ulenRes, bbuf);
2681 }
2682 }
2683 unum_close(unum);
2684 }
2685 #endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */
2686 }
2687
2688 static void TestCurrencyUsage(void) {
2689 static const char* DATA[][2] = {
2690 /* the data are:
2691 * currency ISO code to be formatted,
2692 * format result using CURRENCYSTYLE with CASH purpose,-
2693 * Note that as of CLDR 26:-
2694 * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
2695 * - CAD rounds to .05
2696 */
2697
2698 {"PKR", "PKR124"}, // ICU 61 behavior
2699 {"CAD", "CA$123.55"},
2700 {"USD", "$123.57"}
2701 };
2702
2703 // 1st time for getter/setter, 2nd for factory method
2704 int32_t i;
2705 for(i=0; i<2; i++){
2706 const char* localeString = "en_US";
2707 double numberToBeFormat = 123.567;
2708 UNumberFormat* unumFmt;
2709 UNumberFormatStyle style = UNUM_CURRENCY;
2710 UErrorCode status = U_ZERO_ERROR;
2711 int32_t j;
2712
2713 if(i == 1){ // change for factory method
2714 style = UNUM_CASH_CURRENCY;
2715 }
2716
2717 unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
2718 if (U_FAILURE(status)) {
2719 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2720 localeString, (int)style, myErrorName(status));
2721 continue;
2722 }
2723
2724 if(i == 0){ // this is for the getter/setter
2725 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_STANDARD) {
2726 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n");
2727 }
2728
2729 unum_setAttribute(unumFmt, UNUM_CURRENCY_USAGE, UCURR_USAGE_CASH);
2730 }
2731
2732 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_CASH) {
2733 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n");
2734 }
2735
2736 for (j=0; j<UPRV_LENGTHOF(DATA); ++j) {
2737 UChar expect[64];
2738 int32_t expectLen;
2739 UChar currencyCode[4];
2740 UChar result[64];
2741 int32_t resultLen;
2742 UFieldPosition pos = {0};
2743
2744 u_charsToUChars(DATA[j][0], currencyCode, 3);
2745 expectLen = u_unescape(DATA[j][1], expect, UPRV_LENGTHOF(expect));
2746
2747 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
2748 assertSuccess("num_setTextAttribute()", &status);
2749
2750 resultLen = unum_formatDouble(unumFmt, numberToBeFormat, result, UPRV_LENGTHOF(result),
2751 &pos, &status);
2752 assertSuccess("num_formatDouble()", &status);
2753
2754 if(resultLen != expectLen || u_strcmp(result, expect) != 0) {
2755 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n",
2756 aescstrdup(expect, expectLen), aescstrdup(result, resultLen));
2757 }
2758
2759 }
2760
2761 unum_close(unumFmt);
2762 }
2763 }
2764
2765 static UChar currFmtNegSameAsPos[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */
2766 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2767
2768 static UChar currFmtToPatExpected[] = /* "\u00A4#,##0.00" */ // ICU 61 behavior
2769 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2770
2771 static UChar currFmtResultExpected[] = /* "$100.00" */
2772 {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0};
2773
2774 static UChar emptyString[] = {0};
2775
2776 enum { kUBufSize = 64, kBBufSize = 128 };
2777
2778 static void TestCurrFmtNegSameAsPositive(void) {
2779 UErrorCode status = U_ZERO_ERROR;
2780 UNumberFormat* unumfmt = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
2781 if ( U_SUCCESS(status) ) {
2782 unum_applyPattern(unumfmt, FALSE, currFmtNegSameAsPos, -1, NULL, &status);
2783 if (U_SUCCESS(status)) {
2784 UChar ubuf[kUBufSize];
2785 int32_t ulen = unum_toPattern(unumfmt, FALSE, ubuf, kUBufSize, &status);
2786 if (U_FAILURE(status)) {
2787 log_err("unum_toPattern fails with status %s\n", myErrorName(status));
2788 } else if (u_strcmp(ubuf, currFmtToPatExpected) != 0) {
2789 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected,-1), aescstrdup(ubuf,ulen));
2790 }
2791 unum_setSymbol(unumfmt, UNUM_MINUS_SIGN_SYMBOL, emptyString, 0, &status);
2792 if (U_SUCCESS(status)) {
2793 ulen = unum_formatDouble(unumfmt, -100.0, ubuf, kUBufSize, NULL, &status);
2794 if (U_FAILURE(status)) {
2795 log_err("unum_formatDouble fails with status %s\n", myErrorName(status));
2796 } else if (u_strcmp(ubuf, currFmtResultExpected) != 0) {
2797 log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected,-1), aescstrdup(ubuf,ulen));
2798 }
2799 } else {
2800 log_err("unum_setSymbol fails with status %s\n", myErrorName(status));
2801 }
2802 } else {
2803 log_err("unum_applyPattern fails with status %s\n", myErrorName(status));
2804 }
2805 unum_close(unumfmt);
2806 } else {
2807 log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status));
2808 }
2809 }
2810
2811
2812 typedef struct {
2813 double value;
2814 const char *expected;
2815 } ValueAndExpectedString;
2816
2817 static const ValueAndExpectedString enShort[] = {
2818 {0.0, "0"},
2819 {0.17, "0.17"},
2820 {1.0, "1"},
2821 {1234.0, "1.23K"},
2822 {12345.0, "12.3K"},
2823 {123456.0, "123K"},
2824 {1234567.0, "1.23M"},
2825 {12345678.0, "12.3M"},
2826 {123456789.0, "123M"},
2827 {1.23456789E9, "1.23B"},
2828 {1.23456789E10, "12.3B"},
2829 {1.23456789E11, "123B"},
2830 {1.23456789E12, "1.23T"},
2831 {1.23456789E13, "12.3T"},
2832 {1.23456789E14, "123T"},
2833 {1.23456789E15, "1230T"},
2834 {0.0, NULL}
2835 };
2836
2837 static const ValueAndExpectedString enShortMax2[] = {
2838 {0.0, "0"},
2839 {0.17, "0.17"},
2840 {1.0, "1"},
2841 {1234.0, "1.2K"},
2842 {12345.0, "12K"},
2843 {123456.0, "120K"},
2844 {1234567.0, "1.2M"},
2845 {12345678.0, "12M"},
2846 {123456789.0, "120M"},
2847 {1.23456789E9, "1.2B"},
2848 {1.23456789E10, "12B"},
2849 {1.23456789E11, "120B"},
2850 {1.23456789E12, "1.2T"},
2851 {1.23456789E13, "12T"},
2852 {1.23456789E14, "120T"},
2853 {1.23456789E15, "1200T"},
2854 {0.0, NULL}
2855 };
2856
2857 static const ValueAndExpectedString enShortMax5[] = {
2858 {0.0, "0"},
2859 {0.17, "0.17"},
2860 {1.0, "1"},
2861 {1234.0, "1.234K"},
2862 {12345.0, "12.345K"},
2863 {123456.0, "123.46K"},
2864 {1234567.0, "1.2346M"},
2865 {12345678.0, "12.346M"},
2866 {123456789.0, "123.46M"},
2867 {1.23456789E9, "1.2346B"},
2868 {1.23456789E10, "12.346B"},
2869 {1.23456789E11, "123.46B"},
2870 {1.23456789E12, "1.2346T"},
2871 {1.23456789E13, "12.346T"},
2872 {1.23456789E14, "123.46T"},
2873 {1.23456789E15, "1234.6T"},
2874 {0.0, NULL}
2875 };
2876
2877 static const ValueAndExpectedString enShortMin3[] = {
2878 {0.0, "0.00"},
2879 {0.17, "0.170"},
2880 {1.0, "1.00"},
2881 {1234.0, "1.23K"},
2882 {12345.0, "12.3K"},
2883 {123456.0, "123K"},
2884 {1234567.0, "1.23M"},
2885 {12345678.0, "12.3M"},
2886 {123456789.0, "123M"},
2887 {1.23456789E9, "1.23B"},
2888 {1.23456789E10, "12.3B"},
2889 {1.23456789E11, "123B"},
2890 {1.23456789E12, "1.23T"},
2891 {1.23456789E13, "12.3T"},
2892 {1.23456789E14, "123T"},
2893 {1.23456789E15, "1230T"},
2894 {0.0, NULL}
2895 };
2896
2897 static const ValueAndExpectedString jaShortMax2[] = {
2898 {1234.0, "1200"},
2899 {12345.0, "1.2\\u4E07"},
2900 {123456.0, "12\\u4E07"},
2901 {1234567.0, "120\\u4E07"},
2902 {12345678.0, "1200\\u4E07"},
2903 {123456789.0, "1.2\\u5104"},
2904 {1.23456789E9, "12\\u5104"},
2905 {1.23456789E10, "120\\u5104"},
2906 {1.23456789E11, "1200\\u5104"},
2907 {1.23456789E12, "1.2\\u5146"},
2908 {1.23456789E13, "12\\u5146"},
2909 {1.23456789E14, "120\\u5146"},
2910 {0.0, NULL}
2911 };
2912
2913 static const ValueAndExpectedString srLongMax2[] = {
2914 {1234.0, "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
2915 {12345.0, "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
2916 {21789.0, "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
2917 {123456.0, "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
2918 {999999.0, "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
2919 {1234567.0, "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
2920 {12345678.0, "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
2921 {123456789.0, "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
2922 {1.23456789E9, "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
2923 {1.23456789E10, "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
2924 {2.08901234E10, "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
2925 {2.18901234E10, "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
2926 {1.23456789E11, "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
2927 {-1234.0, "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
2928 {-12345.0, "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
2929 {-21789.0, "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
2930 {-123456.0, "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
2931 {-999999.0, "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
2932 {-1234567.0, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2933 {-12345678.0, "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2934 {-123456789.0, "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
2935 {-1.23456789E9, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
2936 {-1.23456789E10, "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
2937 {-2.08901234E10, "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
2938 {-2.18901234E10, "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
2939 {-1.23456789E11, "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
2940 {0.0, NULL}
2941 };
2942
2943 typedef struct {
2944 const char * locale;
2945 UNumberFormatStyle style;
2946 int32_t attribute; // UNumberFormatAttribute, or -1 for none
2947 int32_t attrValue; //
2948 const ValueAndExpectedString * veItems;
2949 } LocStyleAttributeTest;
2950
2951 static const LocStyleAttributeTest lsaTests[] = {
2952 { "en", UNUM_DECIMAL_COMPACT_SHORT, -1, 0, enShort },
2953 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, enShortMax2 },
2954 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 5, enShortMax5 },
2955 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MIN_SIGNIFICANT_DIGITS, 3, enShortMin3 },
2956 { "ja", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, jaShortMax2 },
2957 { "sr", UNUM_DECIMAL_COMPACT_LONG, UNUM_MAX_SIGNIFICANT_DIGITS, 2, srLongMax2 },
2958 { NULL, (UNumberFormatStyle)0, -1, 0, NULL }
2959 };
2960
2961 static void TestVariousStylesAndAttributes(void) {
2962 const LocStyleAttributeTest * lsaTestPtr;
2963 for (lsaTestPtr = lsaTests; lsaTestPtr->locale != NULL; lsaTestPtr++) {
2964 UErrorCode status = U_ZERO_ERROR;
2965 UNumberFormat * unum = unum_open(lsaTestPtr->style, NULL, 0, lsaTestPtr->locale, NULL, &status);
2966 if ( U_FAILURE(status) ) {
2967 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr->style, lsaTestPtr->locale, u_errorName(status));
2968 } else {
2969 const ValueAndExpectedString * veItemPtr;
2970 if (lsaTestPtr->attribute >= 0) {
2971 unum_setAttribute(unum, (UNumberFormatAttribute)lsaTestPtr->attribute, lsaTestPtr->attrValue);
2972 }
2973 // ICU 62: should call minSignificantDigits in tandem with maxSignificantDigits.
2974 if (lsaTestPtr->attribute == UNUM_MIN_SIGNIFICANT_DIGITS) {
2975 unum_setAttribute(unum, UNUM_MAX_SIGNIFICANT_DIGITS, lsaTestPtr->attrValue);
2976 }
2977 for (veItemPtr = lsaTestPtr->veItems; veItemPtr->expected != NULL; veItemPtr++) {
2978 UChar uexp[kUBufSize];
2979 UChar uget[kUBufSize];
2980 int32_t uexplen, ugetlen;
2981
2982 status = U_ZERO_ERROR;
2983 uexplen = u_unescape(veItemPtr->expected, uexp, kUBufSize);
2984 ugetlen = unum_formatDouble(unum, veItemPtr->value, uget, kUBufSize, NULL, &status);
2985 if ( U_FAILURE(status) ) {
2986 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n",
2987 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, u_errorName(status));
2988 } else if (ugetlen != uexplen || u_strncmp(uget, uexp, uexplen) != 0) {
2989 char bexp[kBBufSize];
2990 char bget[kBBufSize];
2991 u_strToUTF8(bexp, kBBufSize, NULL, uexp, uexplen, &status);
2992 u_strToUTF8(bget, kBBufSize, NULL, uget, ugetlen, &status);
2993 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n",
2994 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, bexp, bget);
2995 }
2996 }
2997 unum_close(unum);
2998 }
2999 }
3000 }
3001
3002 static const UChar currpat[] = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; /* ¤#,##0.00 */
3003 static const UChar parsetxt[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */
3004
3005 static void TestParseCurrPatternWithDecStyle() {
3006 UErrorCode status = U_ZERO_ERROR;
3007 UNumberFormat *unumfmt = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
3008 if (U_FAILURE(status)) {
3009 log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status));
3010 } else {
3011 unum_applyPattern(unumfmt, FALSE, currpat, -1, NULL, &status);
3012 if (U_FAILURE(status)) {
3013 log_err_status(status, "unum_applyPattern failed: %s\n", u_errorName(status));
3014 } else {
3015 int32_t pos = 0;
3016 double value = unum_parseDouble(unumfmt, parsetxt, -1, &pos, &status);
3017 if (U_SUCCESS(status)) {
3018 log_err_status(status, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status), value);
3019 }
3020 }
3021 unum_close(unumfmt);
3022 }
3023 }
3024
3025 /*
3026 * Ticket #12684
3027 * Test unum_formatDoubleForFields (and UFieldPositionIterator)
3028 */
3029
3030 typedef struct {
3031 int32_t field;
3032 int32_t beginPos;
3033 int32_t endPos;
3034 } FieldsData;
3035
3036 typedef struct {
3037 const char * locale;
3038 UNumberFormatStyle style;
3039 double value;
3040 const FieldsData * expectedFields;
3041 } FormatForFieldsItem;
3042
3043 static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
3044
3045
3046 /* "en_US", UNUM_CURRENCY, 123456.0 : "¤#,##0.00" => "$123,456.00" */
3047 static const FieldsData fields_en_CURR[] = {
3048 { UNUM_CURRENCY_FIELD /*7*/, 0, 1 },
3049 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 4, 5 },
3050 { UNUM_INTEGER_FIELD /*0*/, 1, 8 },
3051 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 8, 9 },
3052 { UNUM_FRACTION_FIELD /*1*/, 9, 11 },
3053 { -1, -1, -1 },
3054 };
3055 /* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
3056 static const FieldsData fields_en_PRCT[] = {
3057 { UNUM_SIGN_FIELD /*10*/, 0, 1 },
3058 { UNUM_INTEGER_FIELD /*0*/, 1, 3 },
3059 { UNUM_PERCENT_FIELD /*8*/, 3, 4 },
3060 { -1, -1, -1 },
3061 };
3062 /* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00 ¤" => "123,456.00 €" */
3063 static const FieldsData fields_fr_CURR[] = {
3064 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 3, 4 },
3065 { UNUM_INTEGER_FIELD /*0*/, 0, 7 },
3066 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 7, 8 },
3067 { UNUM_FRACTION_FIELD /*1*/, 8, 10 },
3068 { UNUM_CURRENCY_FIELD /*7*/, 11, 12 },
3069 { -1, -1, -1 },
3070 };
3071 /* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
3072 static const FieldsData fields_en_PATN[] = {
3073 { UNUM_INTEGER_FIELD /*0*/, 1, 3 },
3074 { -1, -1, -1 },
3075 };
3076
3077 static const FormatForFieldsItem fffItems[] = {
3078 { "en_US", UNUM_CURRENCY_STANDARD, 123456.0, fields_en_CURR },
3079 { "en_US", UNUM_PERCENT, -0.34, fields_en_PRCT },
3080 { "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR },
3081 { "en_US", UNUM_PATTERN_DECIMAL, 12.0, fields_en_PATN },
3082 { NULL, (UNumberFormatStyle)0, 0, NULL },
3083 };
3084
3085 static void TestFormatForFields(void) {
3086 UErrorCode status = U_ZERO_ERROR;
3087 UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
3088 if ( U_FAILURE(status) ) {
3089 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
3090 } else {
3091 const FormatForFieldsItem * itemPtr;
3092 for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) {
3093 UNumberFormat* unum;
3094 status = U_ZERO_ERROR;
3095 unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)?
3096 unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status):
3097 unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
3098 if ( U_FAILURE(status) ) {
3099 log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3100 } else {
3101 UChar ubuf[kUBufSize];
3102 int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status);
3103 if ( U_FAILURE(status) ) {
3104 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3105 } else {
3106 const FieldsData * fptr;
3107 int32_t field, beginPos, endPos;
3108 for (fptr = itemPtr->expectedFields; TRUE; fptr++) {
3109 field = ufieldpositer_next(fpositer, &beginPos, &endPos);
3110 if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
3111 if (fptr->field >= 0) {
3112 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
3113 itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
3114 } else {
3115 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
3116 itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos);
3117 }
3118 break;
3119 }
3120 if (field < 0) {
3121 break;
3122 }
3123 }
3124 }
3125 unum_close(unum);
3126 }
3127 }
3128 ufieldpositer_close(fpositer);
3129 }
3130 }
3131
3132 static void Test12052_NullPointer() {
3133 UErrorCode status = U_ZERO_ERROR;
3134 static const UChar input[] = u"199a";
3135 UChar currency[200] = {0};
3136 UNumberFormat *theFormatter = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
3137 if (!assertSuccessCheck("unum_open() failed", &status, TRUE)) { return; }
3138 status = U_ZERO_ERROR;
3139 unum_setAttribute(theFormatter, UNUM_LENIENT_PARSE, 1);
3140 int32_t pos = 1;
3141 unum_parseDoubleCurrency(theFormatter, input, -1, &pos, currency, &status);
3142 assertEquals("should fail gracefully", "U_PARSE_ERROR", u_errorName(status));
3143 unum_close(theFormatter);
3144 }
3145
3146 typedef struct {
3147 const char* locale;
3148 const UChar* text; // text to parse
3149 UBool lenient; // leniency to use
3150 UErrorCode intStatus; // expected status from parse
3151 int32_t intPos; // expected final pos from parse
3152 int32_t intValue; // expected value from parse
3153 UErrorCode doubStatus; // expected status from parseDouble
3154 int32_t doubPos; // expected final pos from parseDouble
3155 double doubValue; // expected value from parseDouble
3156 } ParseCaseItem;
3157
3158 static const ParseCaseItem parseCaseItems[] = {
3159 { "en", u"0,000", FALSE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0 },
3160 { "en", u"0,000", TRUE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0 },
3161 { "en", u",024", FALSE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0 },
3162 { "en", u",024", TRUE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0 },
3163 { "en", u"1000,000", FALSE, U_ZERO_ERROR, 8, 1000000, U_ZERO_ERROR, 8, 1000000.0 },
3164 { "en", u"1000,000", TRUE, U_ZERO_ERROR, 8, 1000000, U_ZERO_ERROR, 8, 1000000.0 },
3165 { NULL, NULL, 0, 0, 0, 0, 0, 0, 0.0 }
3166 };
3167
3168 // Currently Apple only
3169 static void TestParseCases(void) {
3170 const ParseCaseItem* itemPtr;
3171 for (itemPtr = parseCaseItems; itemPtr->locale != NULL; itemPtr++) {
3172 UErrorCode status = U_ZERO_ERROR;
3173 UNumberFormat* unumDec = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status);
3174 if (U_FAILURE(status)) {
3175 log_data_err("unum_open UNUM_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3176 continue;
3177 }
3178 int32_t intValue, parsePos;
3179 double doubValue;
3180 unum_setAttribute(unumDec, UNUM_LENIENT_PARSE, itemPtr->lenient);
3181
3182 parsePos = 0;
3183 status = U_ZERO_ERROR;
3184 intValue = unum_parse(unumDec, itemPtr->text, -1, &parsePos, &status);
3185 if (status != itemPtr->intStatus || parsePos != itemPtr->intPos || intValue != itemPtr->intValue) {
3186 char btext[32];
3187 u_austrcpy(btext, itemPtr->text);
3188 log_err("locale %s, text \"%s\", lenient %d;\n parse expected status %s, pos %d, value %d;\n got %s, %d, %d\n",
3189 itemPtr->locale, btext, itemPtr->lenient, u_errorName(itemPtr->intStatus), itemPtr->intPos, itemPtr->intValue,
3190 u_errorName(status), parsePos, intValue);
3191 }
3192
3193 parsePos = 0;
3194 status = U_ZERO_ERROR;
3195 doubValue = unum_parseDouble(unumDec, itemPtr->text, -1, &parsePos, &status);
3196 if (status != itemPtr->doubStatus || parsePos != itemPtr->doubPos || doubValue != itemPtr->doubValue) {
3197 char btext[32];
3198 u_austrcpy(btext, itemPtr->text);
3199 log_err("locale %s, text \"%s\", lenient %d;\n parseDouble expected status %s, pos %d, value %.1f;\n got %s, %d, %.1f\n",
3200 itemPtr->locale, btext, itemPtr->lenient, u_errorName(itemPtr->doubStatus), itemPtr->doubPos, itemPtr->doubValue,
3201 u_errorName(status), parsePos, doubValue);
3202 }
3203 }
3204 }
3205
3206 typedef struct {
3207 const char* locale;
3208 double value;
3209 const UChar* formatLimitPrecision;
3210 const UChar* formatFullPrecision;
3211 } FormatPrecisionItem;
3212
3213 static const FormatPrecisionItem formatPrecisionItems[] = {
3214 { "en_US", 0.33333333 - 0.00333333, u"0.33", u"0.32999999999999996" },
3215 { "en_US", 0.07 * 100.0, u"7", u"7.000000000000001" },
3216 { NULL, 0.0, NULL, NULL }
3217 };
3218
3219 static const UChar* patternTestPrecision = u"#0.################################################################################"; // 80 fraction places
3220
3221 // Currently Apple only
3222 static void TestFormatPrecision(void) {
3223 const FormatPrecisionItem* itemPtr;
3224 for (itemPtr = formatPrecisionItems; itemPtr->locale != NULL; itemPtr++) {
3225 UErrorCode status = U_ZERO_ERROR;
3226 UParseError perr;
3227 UNumberFormat *unum = unum_open(UNUM_PATTERN_DECIMAL, patternTestPrecision, -1, itemPtr->locale, &perr, &status);
3228 if (U_FAILURE(status)) {
3229 log_data_err("unum_open UNUM_PATTERN_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3230 continue;
3231 }
3232 UChar ubuf[kUBufSize];
3233 int32_t ulen;
3234 UFieldPosition fpos;
3235 UBool formatFullPrecision;
3236
3237 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3238 if (formatFullPrecision) {
3239 log_err("unum_getAttribute, default for UNUM_FORMAT_WITH_FULL_PRECISION is not FALSE\n");
3240 } else {
3241 status = U_ZERO_ERROR;
3242 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3243 if (U_FAILURE(status)) {
3244 log_err("unum_formatDouble locale %s val %.20f limit precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3245 } else if (ulen != u_strlen(itemPtr->formatLimitPrecision) || u_strcmp(ubuf, itemPtr->formatLimitPrecision) != 0) {
3246 char bbufe[kBBufSize];
3247 char bbufg[kBBufSize];
3248 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatLimitPrecision, -1, &status);
3249 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3250 log_err("unum_formatDouble locale %s val %.20f limit precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3251 }
3252 }
3253
3254 unum_setAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION, TRUE);
3255 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3256 if (!formatFullPrecision) {
3257 log_err("unum_getAttribute, after set UNUM_FORMAT_WITH_FULL_PRECISION is not TRUE\n");
3258 } else {
3259 status = U_ZERO_ERROR;
3260 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3261 if (U_FAILURE(status)) {
3262 log_err("unum_formatDouble locale %s val %.20f full precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3263 } else if (ulen != u_strlen(itemPtr->formatFullPrecision) || u_strcmp(ubuf, itemPtr->formatFullPrecision) != 0) {
3264 char bbufe[kBBufSize];
3265 char bbufg[kBBufSize];
3266 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatFullPrecision, -1, &status);
3267 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3268 log_err("unum_formatDouble locale %s val %.20f full precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3269 }
3270 }
3271
3272 unum_close(unum);
3273 }
3274 }
3275
3276 #endif /* #if !UCONFIG_NO_FORMATTING */