]> git.saurik.com Git - apple/icu.git/blame_incremental - icuSources/test/cintltst/cnumtst.c
ICU-64252.0.1.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cnumtst.c
... / ...
CommitLineData
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#include "unicode/uchar.h"
35
36#include "cintltst.h"
37#include "cnumtst.h"
38#include "cmemory.h"
39#include "cstring.h"
40#include "putilimp.h"
41#include "uassert.h"
42#include <stdio.h>
43#include <stdlib.h>
44
45#define APPLE_ADDITIONS 1
46
47static const char *tagAssert(const char *f, int32_t l, const char *msg) {
48 static char _fileline[1000];
49 sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg);
50 return _fileline;
51}
52
53#define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x))
54
55void addNumForTest(TestNode** root);
56static void TestTextAttributeCrash(void);
57static void TestNBSPInPattern(void);
58static void TestInt64Parse(void);
59static void TestParseCurrency(void);
60static void TestMaxInt(void);
61static void TestNoExponent(void);
62static void TestSignAlwaysShown(void);
63static void TestMinimumGroupingDigits(void);
64static void TestParseCaseSensitive(void);
65static void TestUFormattable(void);
66static void TestUNumberingSystem(void);
67static void TestCurrencyIsoPluralFormat(void);
68static void TestContext(void);
69static void TestCurrencyUsage(void);
70static void TestCurrFmtNegSameAsPositive(void);
71static void TestVariousStylesAndAttributes(void);
72static void TestParseCurrPatternWithDecStyle(void);
73static void TestFormatForFields(void);
74static void TestRBNFRounding(void);
75static void Test12052_NullPointer(void);
76static void TestParseCases(void);
77static void TestSetMaxFracAndRoundIncr(void);
78static void TestIgnorePadding(void);
79static void TestParseAltNum(void);
80static void TestParseCurrPatternWithDecStyle(void);
81static void TestFormatPrecision(void);
82static void TestSetSigDigAndRoundIncr(void); // Apple <rdar://problem/52538227>
83static void TestSetAffixOnCurrFmt(void); // Apple <rdar://problem/46755430>
84static void TestParseWithEmptyCurr(void); // Apple <rdar://problem/46915356>
85static void TestSciNotationNumbers(void); // Apple <rdar://problem/50113359>
86static void TestSciNotationPrecision(void); // Apple <rdar://problem/51601250>
87static void TestMinimumGrouping(void); // Apple <rdar://problem/49808819>
88static void TestNumberSystemsMultiplier(void); // Apple <rdar://problem/49120648>
89static void TestParseScientific(void); // Apple <rdar://problem/39156484>
90static void TestCurrForUnkRegion(void); // Apple <rdar://problem/51985640>
91static void TestMinIntMinFracZero(void); // Apple <rdar://problem/54569257>
92#if APPLE_ADDITIONS
93static void TestFormatDecPerf(void); // Apple <rdar://problem/51672521>
94#endif
95
96#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
97
98void addNumForTest(TestNode** root)
99{
100 TESTCASE(TestNumberFormat);
101 TESTCASE(TestSpelloutNumberParse);
102 TESTCASE(TestSignificantDigits);
103 TESTCASE(TestSigDigRounding);
104 TESTCASE(TestNumberFormatPadding);
105 TESTCASE(TestInt64Format);
106 TESTCASE(TestNonExistentCurrency);
107 TESTCASE(TestCurrencyRegression);
108 TESTCASE(TestTextAttributeCrash);
109 TESTCASE(TestRBNFFormat);
110 TESTCASE(TestRBNFRounding);
111 TESTCASE(TestNBSPInPattern);
112 TESTCASE(TestInt64Parse);
113 TESTCASE(TestParseZero);
114 TESTCASE(TestParseCurrency);
115 TESTCASE(TestCloneWithRBNF);
116 TESTCASE(TestMaxInt);
117 TESTCASE(TestNoExponent);
118 TESTCASE(TestSignAlwaysShown);
119 TESTCASE(TestMinimumGroupingDigits);
120 TESTCASE(TestParseCaseSensitive);
121 TESTCASE(TestUFormattable);
122 TESTCASE(TestUNumberingSystem);
123 TESTCASE(TestCurrencyIsoPluralFormat);
124 TESTCASE(TestContext);
125 TESTCASE(TestCurrencyUsage);
126 TESTCASE(TestCurrFmtNegSameAsPositive);
127 TESTCASE(TestVariousStylesAndAttributes);
128 TESTCASE(TestParseCurrPatternWithDecStyle);
129 TESTCASE(TestFormatForFields);
130 TESTCASE(Test12052_NullPointer);
131 TESTCASE(TestParseCases);
132 TESTCASE(TestSetMaxFracAndRoundIncr);
133 TESTCASE(TestIgnorePadding);
134 TESTCASE(TestParseAltNum);
135 TESTCASE(TestParseCurrPatternWithDecStyle);
136 TESTCASE(TestFormatPrecision);
137 TESTCASE(TestSetSigDigAndRoundIncr); // Apple <rdar://problem/52538227>
138 TESTCASE(TestSetAffixOnCurrFmt); // Apple <rdar://problem/46755430>
139 TESTCASE(TestParseWithEmptyCurr); // Apple <rdar://problem/46915356>
140 TESTCASE(TestSciNotationNumbers); // Apple <rdar://problem/50113359>
141 TESTCASE(TestSciNotationPrecision); // Apple <rdar://problem/51601250>
142 TESTCASE(TestMinimumGrouping); // Apple <rdar://problem/49808819>
143 TESTCASE(TestNumberSystemsMultiplier); // Apple <rdar://problem/49120648>
144 TESTCASE(TestParseScientific); // Apple <rdar://problem/39156484>
145 TESTCASE(TestCurrForUnkRegion); // Apple <rdar://problem/51985640>
146 TESTCASE(TestMinIntMinFracZero); // Apple <rdar://problem/54569257>
147#if APPLE_ADDITIONS
148 TESTCASE(TestFormatDecPerf); // Apple <rdar://problem/51672521>
149#endif
150}
151
152/* test Parse int 64 */
153
154static void TestInt64Parse()
155{
156
157 UErrorCode st = U_ZERO_ERROR;
158 UErrorCode* status = &st;
159
160 const char* st1 = "009223372036854775808";
161 const int size = 21;
162 UChar text[21];
163
164
165 UNumberFormat* nf;
166
167 int64_t a;
168
169 u_charsToUChars(st1, text, size);
170 nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status);
171
172 if(U_FAILURE(*status))
173 {
174 log_data_err("Error in unum_open() %s \n", myErrorName(*status));
175 return;
176 }
177
178 log_verbose("About to test unum_parseInt64() with out of range number\n");
179
180 a = unum_parseInt64(nf, text, size, 0, status);
181 (void)a; /* Suppress set but not used warning. */
182
183
184 if(!U_FAILURE(*status))
185 {
186 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status));
187 }
188 else
189 {
190 log_verbose("unum_parseInt64() successful\n");
191 }
192
193 unum_close(nf);
194 return;
195}
196
197/* test Number Format API */
198static void TestNumberFormat()
199{
200 UChar *result=NULL;
201 UChar temp1[512];
202 UChar temp2[512];
203
204 UChar temp[5];
205
206 UChar prefix[5];
207 UChar suffix[5];
208 UChar symbol[20];
209 int32_t resultlength;
210 int32_t resultlengthneeded;
211 int32_t parsepos;
212 double d1 = -1.0;
213 int32_t l1;
214 double d = -10456.37;
215 double a = 1234.56, a1 = 1235.0;
216 int32_t l = 100000000;
217 UFieldPosition pos1;
218 UFieldPosition pos2;
219 int32_t numlocales;
220 int32_t i;
221
222 UNumberFormatAttribute attr;
223 UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL;
224 int32_t newvalue;
225 UErrorCode status=U_ZERO_ERROR;
226 UNumberFormatStyle style= UNUM_DEFAULT;
227 UNumberFormat *pattern;
228 UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr,
229 *cur_frpattern, *myclone, *spellout_def;
230
231 /* Testing unum_open() with various Numberformat styles and locales*/
232 status = U_ZERO_ERROR;
233 log_verbose("Testing unum_open() with default style and locale\n");
234 def=unum_open(style, NULL,0,NULL, NULL,&status);
235
236 /* Might as well pack it in now if we can't even get a default NumberFormat... */
237 if(U_FAILURE(status))
238 {
239 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
240 return;
241 }
242
243 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n");
244 fr=unum_open(style,NULL,0, "fr_FR",NULL, &status);
245 if(U_FAILURE(status))
246 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status));
247
248 log_verbose("\nTesting unum_open(currency,NULL,status)\n");
249 style=UNUM_CURRENCY;
250 /* Can't hardcode the result to assume the default locale is "en_US". */
251 cur_def=unum_open(style, NULL,0,"en_US", NULL, &status);
252 if(U_FAILURE(status))
253 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n",
254 myErrorName(status) );
255
256 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n");
257 cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status);
258 if(U_FAILURE(status))
259 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
260 myErrorName(status));
261
262 log_verbose("\nTesting unum_open(percent, NULL, status)\n");
263 style=UNUM_PERCENT;
264 per_def=unum_open(style,NULL,0, NULL,NULL, &status);
265 if(U_FAILURE(status))
266 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status));
267
268 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n");
269 per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status);
270 if(U_FAILURE(status))
271 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status));
272
273 log_verbose("\nTesting unum_open(spellout, NULL, status)");
274 style=UNUM_SPELLOUT;
275 spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status);
276 if(U_FAILURE(status))
277 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status));
278
279 /* Testing unum_clone(..) */
280 log_verbose("\nTesting unum_clone(fmt, status)");
281 status = U_ZERO_ERROR;
282 myclone = unum_clone(def,&status);
283 if(U_FAILURE(status))
284 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status));
285 else
286 {
287 log_verbose("unum_clone() successful\n");
288 }
289
290 /*Testing unum_getAvailable() and unum_countAvailable()*/
291 log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
292 numlocales=unum_countAvailable();
293 if(numlocales < 0)
294 log_err("error in countAvailable");
295 else{
296 log_verbose("unum_countAvialable() successful\n");
297 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales);
298 }
299 for(i=0;i<numlocales;i++)
300 {
301 log_verbose("%s\n", unum_getAvailable(i));
302 if (unum_getAvailable(i) == 0)
303 log_err("No locale for which number formatting patterns are applicable\n");
304 else
305 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i));
306 }
307
308
309 /*Testing unum_format() and unum_formatdouble()*/
310 u_uastrcpy(temp1, "$100,000,000.00");
311
312 log_verbose("\nTesting unum_format() \n");
313 resultlength=0;
314 pos1.field = UNUM_INTEGER_FIELD;
315 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
316 if(status==U_BUFFER_OVERFLOW_ERROR)
317 {
318 status=U_ZERO_ERROR;
319 resultlength=resultlengthneeded+1;
320 result=(UChar*)malloc(sizeof(UChar) * resultlength);
321/* for (i = 0; i < 100000; i++) */
322 {
323 unum_format(cur_def, l, result, resultlength, &pos1, &status);
324 }
325 }
326
327 if(U_FAILURE(status))
328 {
329 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) );
330 }
331 if(u_strcmp(result, temp1)==0)
332 log_verbose("Pass: Number formatting using unum_format() successful\n");
333 else
334 log_err("Fail: Error in number Formatting using unum_format()\n");
335 if(pos1.beginIndex == 1 && pos1.endIndex == 12)
336 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
337 else
338 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n",
339 pos1.beginIndex, pos1.endIndex);
340
341 free(result);
342 result = 0;
343
344 log_verbose("\nTesting unum_formatDouble()\n");
345 u_uastrcpy(temp1, "-$10,456.37");
346 resultlength=0;
347 pos2.field = UNUM_FRACTION_FIELD;
348 resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status);
349 if(status==U_BUFFER_OVERFLOW_ERROR)
350 {
351 status=U_ZERO_ERROR;
352 resultlength=resultlengthneeded+1;
353 result=(UChar*)malloc(sizeof(UChar) * resultlength);
354/* for (i = 0; i < 100000; i++) */
355 {
356 unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status);
357 }
358 }
359 if(U_FAILURE(status))
360 {
361 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
362 }
363 if(result && u_strcmp(result, temp1)==0)
364 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
365 else {
366 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n",
367 aescstrdup(result, -1), aescstrdup(temp1, -1));
368 }
369 if(pos2.beginIndex == 9 && pos2.endIndex == 11)
370 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
371 else
372 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11",
373 pos1.beginIndex, pos1.endIndex);
374
375
376 /* Testing unum_parse() and unum_parseDouble() */
377 log_verbose("\nTesting unum_parseDouble()\n");
378/* for (i = 0; i < 100000; i++)*/
379 parsepos=0;
380 if (result != NULL) {
381 d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status);
382 } else {
383 log_err("result is NULL\n");
384 }
385 if(U_FAILURE(status)) {
386 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status));
387 }
388
389 if(d1!=d)
390 log_err("Fail: Error in parsing\n");
391 else
392 log_verbose("Pass: parsing successful\n");
393 if (result)
394 free(result);
395 result = 0;
396
397 status = U_ZERO_ERROR;
398 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */
399 log_verbose("\nTesting unum_formatDoubleCurrency\n");
400 u_uastrcpy(temp1, "Y1,235");
401 temp1[0] = 0xA5; /* Yen sign */
402 u_uastrcpy(temp, "JPY");
403 resultlength=0;
404 pos2.field = UNUM_INTEGER_FIELD;
405 resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status);
406 if (status==U_BUFFER_OVERFLOW_ERROR) {
407 status=U_ZERO_ERROR;
408 resultlength=resultlengthneeded+1;
409 result=(UChar*)malloc(sizeof(UChar) * resultlength);
410 unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status);
411 }
412 if (U_FAILURE(status)) {
413 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
414 }
415 if (result && u_strcmp(result, temp1)==0) {
416 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
417 } else {
418 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
419 aescstrdup(result, -1), aescstrdup(temp1, -1));
420 }
421 if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
422 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
423 } else {
424 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
425 pos1.beginIndex, pos1.endIndex);
426 }
427
428 log_verbose("\nTesting unum_parseDoubleCurrency\n");
429 parsepos=0;
430 if (result == NULL) {
431 log_err("result is NULL\n");
432 }
433 else {
434 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
435 if (U_FAILURE(status)) {
436 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
437 }
438 /* Note: a==1234.56, but on parse expect a1=1235.0 */
439 if (d1!=a1) {
440 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1);
441 } else {
442 log_verbose("Pass: parsed currency amount successfully\n");
443 }
444 if (u_strcmp(temp2, temp)==0) {
445 log_verbose("Pass: parsed correct currency\n");
446 } else {
447 log_err("Fail: parsed incorrect currency\n");
448 }
449 }
450 status = U_ZERO_ERROR; /* reset */
451
452 free(result);
453 result = 0;
454
455
456/* performance testing */
457 u_uastrcpy(temp1, "$462.12345");
458 resultlength=u_strlen(temp1);
459/* for (i = 0; i < 100000; i++) */
460 {
461 parsepos=0;
462 d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status);
463 }
464 if(U_FAILURE(status))
465 {
466 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
467 }
468
469 /*
470 * Note: "for strict standard conformance all operations and constants are now supposed to be
471 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932.
472 */
473 a1 = 462.12345;
474
475 if(d1!=a1)
476 log_err("Fail: Error in parsing\n");
477 else
478 log_verbose("Pass: parsing successful\n");
479
480free(result);
481
482 u_uastrcpy(temp1, "($10,456.3E1])");
483 parsepos=0;
484 d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status);
485 if(U_SUCCESS(status))
486 {
487 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status));
488 }
489
490
491 log_verbose("\nTesting unum_format()\n");
492 status=U_ZERO_ERROR;
493 resultlength=0;
494 parsepos=0;
495 resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status);
496 if(status==U_BUFFER_OVERFLOW_ERROR)
497 {
498 status=U_ZERO_ERROR;
499 resultlength=resultlengthneeded+1;
500 result=(UChar*)malloc(sizeof(UChar) * resultlength);
501/* for (i = 0; i < 100000; i++)*/
502 {
503 unum_format(per_fr, l, result, resultlength, &pos1, &status);
504 }
505 }
506 if(U_FAILURE(status))
507 {
508 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
509 }
510
511
512 log_verbose("\nTesting unum_parse()\n");
513/* for (i = 0; i < 100000; i++) */
514 {
515 parsepos=0;
516 l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status);
517 }
518 if(U_FAILURE(status))
519 {
520 log_err("parse failed. The error is : %s\n", myErrorName(status));
521 }
522
523 if(l1!=l)
524 log_err("Fail: Error in parsing\n");
525 else
526 log_verbose("Pass: parsing successful\n");
527
528free(result);
529
530 /* create a number format using unum_openPattern(....)*/
531 log_verbose("\nTesting unum_openPattern()\n");
532 u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)");
533 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
534 if(U_FAILURE(status))
535 {
536 log_err("error in unum_openPattern(): %s\n", myErrorName(status) );;
537 }
538 else
539 log_verbose("Pass: unum_openPattern() works fine\n");
540
541 /*test for unum_toPattern()*/
542 log_verbose("\nTesting unum_toPattern()\n");
543 resultlength=0;
544 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
545 if(status==U_BUFFER_OVERFLOW_ERROR)
546 {
547 status=U_ZERO_ERROR;
548 resultlength=resultlengthneeded+1;
549 result=(UChar*)malloc(sizeof(UChar) * resultlength);
550 unum_toPattern(pattern, FALSE, result, resultlength, &status);
551 }
552 if(U_FAILURE(status))
553 {
554 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
555 }
556 else
557 {
558 if(u_strcmp(result, temp1)!=0)
559 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n");
560 else
561 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n");
562free(result);
563 }
564
565 /*Testing unum_getSymbols() and unum_setSymbols()*/
566 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n");
567 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */
568 resultlength=0;
569 resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status);
570 if(status==U_BUFFER_OVERFLOW_ERROR)
571 {
572 status=U_ZERO_ERROR;
573 resultlength=resultlengthneeded+1;
574 result=(UChar*)malloc(sizeof(UChar) * resultlength);
575 unum_toPattern(cur_def, FALSE, result, resultlength, &status);
576 }
577 if(U_FAILURE(status))
578 {
579 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status));
580 }
581
582 status=U_ZERO_ERROR;
583 cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status);
584 if(U_FAILURE(status))
585 {
586 log_err("error in unum_openPattern(): %s\n", myErrorName(status));
587 }
588
589free(result);
590
591 /*getting the symbols of cur_def */
592 /*set the symbols of cur_frpattern to cur_def */
593 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
594 status=U_ZERO_ERROR;
595 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
596 unum_setSymbol(cur_frpattern, symType, temp1, -1, &status);
597 if(U_FAILURE(status))
598 {
599 log_err("Error in get/set symbols: %s\n", myErrorName(status));
600 }
601 }
602
603 /*format to check the result */
604 resultlength=0;
605 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status);
606 if(status==U_BUFFER_OVERFLOW_ERROR)
607 {
608 status=U_ZERO_ERROR;
609 resultlength=resultlengthneeded+1;
610 result=(UChar*)malloc(sizeof(UChar) * resultlength);
611 unum_format(cur_def, l, result, resultlength, &pos1, &status);
612 }
613 if(U_FAILURE(status))
614 {
615 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
616 }
617
618 if(U_FAILURE(status)){
619 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status));
620 }
621 unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL);
622
623 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) {
624 status=U_ZERO_ERROR;
625 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status);
626 unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status);
627 if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0)
628 {
629 log_err("Fail: error in getting symbols\n");
630 }
631 else
632 log_verbose("Pass: get and set symbols successful\n");
633 }
634
635 /*format and check with the previous result */
636
637 resultlength=0;
638 resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status);
639 if(status==U_BUFFER_OVERFLOW_ERROR)
640 {
641 status=U_ZERO_ERROR;
642 resultlength=resultlengthneeded+1;
643 unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status);
644 }
645 if(U_FAILURE(status))
646 {
647 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status));
648 }
649 /* TODO:
650 * This test fails because we have not called unum_applyPattern().
651 * Currently, such an applyPattern() does not exist on the C API, and
652 * we have jitterbug 411 for it.
653 * Since it is close to the 1.5 release, I (markus) am disabling this test just
654 * for this release (I added the test itself only last week).
655 * For the next release, we need to fix this.
656 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file.
657 */
658 if(u_strcmp(result, temp1) != 0) {
659 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1);
660 }
661
662
663 /*----------- */
664
665free(result);
666
667 /* Testing unum_get/setSymbol() */
668 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
669 symbol[0] = (UChar)(0x41 + i);
670 symbol[1] = (UChar)(0x61 + i);
671 unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status);
672 if(U_FAILURE(status)) {
673 log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status));
674 return;
675 }
676 }
677 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) {
678 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
679 if(U_FAILURE(status)) {
680 log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status));
681 return;
682 }
683 if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) {
684 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i);
685 }
686 }
687 /*try getting from a bogus symbol*/
688 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
689 if(U_SUCCESS(status)){
690 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol");
691 }
692 if(U_FAILURE(status)){
693 if(status != U_ILLEGAL_ARGUMENT_ERROR){
694 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status));
695 }
696 }
697 status=U_ZERO_ERROR;
698
699 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/
700 log_verbose("\nTesting getting and setting text attributes\n");
701 resultlength=5;
702 unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
703 if(U_FAILURE(status))
704 {
705 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
706 }
707 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
708 if(U_FAILURE(status))
709 {
710 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
711 }
712 unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status);
713 if(U_FAILURE(status))
714 {
715 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status));
716 }
717 if(u_strcmp(suffix,temp)!=0)
718 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n");
719 else
720 log_verbose("Pass: setting and getting suffix works fine\n");
721 /*set it back to normal */
722 u_uastrcpy(temp,"$");
723 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status);
724
725 /*checking some more text setter conditions */
726 u_uastrcpy(prefix, "+");
727 unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status);
728 if(U_FAILURE(status))
729 {
730 log_err("error in setting the text attributes : %s\n", myErrorName(status));
731 }
732 unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status);
733 if(U_FAILURE(status))
734 {
735 log_err("error in getting the text attributes : %s\n", myErrorName(status));
736 }
737
738 if(u_strcmp(prefix, temp)!=0)
739 log_err("ERROR: get and setTextAttributes with positive prefix failed\n");
740 else
741 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n");
742
743 u_uastrcpy(prefix, "+");
744 unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status);
745 if(U_FAILURE(status))
746 {
747 log_err("error in setting the text attributes : %s\n", myErrorName(status));
748 }
749 unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status);
750 if(U_FAILURE(status))
751 {
752 log_err("error in getting the text attributes : %s\n", myErrorName(status));
753 }
754 if(u_strcmp(prefix, temp)!=0)
755 log_err("ERROR: get and setTextAttributes with negative prefix failed\n");
756 else
757 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n");
758
759 u_uastrcpy(suffix, "+");
760 unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
761 if(U_FAILURE(status))
762 {
763 log_err("error in setting the text attributes: %s\n", myErrorName(status));
764 }
765
766 unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status);
767 if(U_FAILURE(status))
768 {
769 log_err("error in getting the text attributes : %s\n", myErrorName(status));
770 }
771 if(u_strcmp(suffix, temp)!=0)
772 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
773 else
774 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
775
776 u_uastrcpy(suffix, "++");
777 unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status);
778 if(U_FAILURE(status))
779 {
780 log_err("error in setting the text attributes: %s\n", myErrorName(status));
781 }
782
783 unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status);
784 if(U_FAILURE(status))
785 {
786 log_err("error in getting the text attributes : %s\n", myErrorName(status));
787 }
788 if(u_strcmp(suffix, temp)!=0)
789 log_err("ERROR: get and setTextAttributes with negative suffix failed\n");
790 else
791 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n");
792
793 /*Testing unum_getAttribute and unum_setAttribute() */
794 log_verbose("\nTesting get and set Attributes\n");
795 attr=UNUM_GROUPING_SIZE;
796 newvalue=unum_getAttribute(def, attr);
797 newvalue=2;
798 unum_setAttribute(def, attr, newvalue);
799 if(unum_getAttribute(def,attr)!=2)
800 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n");
801 else
802 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n");
803
804 attr=UNUM_MULTIPLIER;
805 newvalue=unum_getAttribute(def, attr);
806 newvalue=8;
807 unum_setAttribute(def, attr, newvalue);
808 if(unum_getAttribute(def,attr) != 8)
809 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n");
810 else
811 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n");
812
813 attr=UNUM_SECONDARY_GROUPING_SIZE;
814 newvalue=unum_getAttribute(def, attr);
815 newvalue=2;
816 unum_setAttribute(def, attr, newvalue);
817 if(unum_getAttribute(def,attr) != 2)
818 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
819 unum_getAttribute(def,attr));
820 else
821 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
822
823 /*testing set and get Attributes extensively */
824 log_verbose("\nTesting get and set attributes extensively\n");
825 for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) )
826 {
827 newvalue=unum_getAttribute(fr, attr);
828 unum_setAttribute(def, attr, newvalue);
829 if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr))
830 log_err("error in setting and getting attributes\n");
831 else
832 log_verbose("Pass: attributes set and retrieved successfully\n");
833 }
834
835 /*testing spellout format to make sure we can use it successfully.*/
836 log_verbose("\nTesting spellout format\n");
837 if (spellout_def)
838 {
839 static const int32_t values[] = { 0, -5, 105, 1005, 105050 };
840 for (i = 0; i < UPRV_LENGTHOF(values); ++i) {
841 UChar buffer[128];
842 int32_t len;
843 int32_t value = values[i];
844 status = U_ZERO_ERROR;
845 len = unum_format(spellout_def, value, buffer, UPRV_LENGTHOF(buffer), NULL, &status);
846 if(U_FAILURE(status)) {
847 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
848 } else {
849 int32_t pp = 0;
850 int32_t parseResult;
851 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
852 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
853
854 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status);
855 if (U_FAILURE(status)) {
856 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status));
857 } else if (parseResult != value) {
858 log_err("unum_format result %d != value %d\n", parseResult, value);
859 }
860 }
861 }
862 }
863 else {
864 log_err("Spellout format is unavailable\n");
865 }
866
867 { /* Test for ticket #7079 */
868 UNumberFormat* dec_en;
869 UChar groupingSep[] = { 0 };
870 UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */
871 double parseResult = 0.0;
872
873 status=U_ZERO_ERROR;
874 dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
875 unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0);
876 unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status);
877 parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status);
878 /* Without the fix in #7079, the above call will hang */
879 if ( U_FAILURE(status) || parseResult != 12.0 ) {
880 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n",
881 myErrorName(status), parseResult);
882 } else {
883 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n");
884 }
885 unum_close(dec_en);
886 }
887
888 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double,
889 to verify that it is taking the pure decimal path. */
890 UNumberFormat *fmt;
891 const char *bdpattern = "#,##0.#########";
892 const char *numInitial = "12345678900987654321.1234567896";
893 const char *numFormatted = "12,345,678,900,987,654,321.12345679";
894 const char *parseExpected = "1.234567890098765432112345679E+19";
895 const char *parseExpected2 = "3.4567890098765432112345679E+17";
896 int32_t resultSize = 0;
897 int32_t parsePos = 0; /* Output parameter for Parse operations. */
898 #define DESTCAPACITY 100
899 UChar dest[DESTCAPACITY];
900 char desta[DESTCAPACITY];
901 UFieldPosition fieldPos = {0};
902
903 /* Format */
904
905 status = U_ZERO_ERROR;
906 u_uastrcpy(dest, bdpattern);
907 fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status);
908 if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
909
910 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status);
911 if (U_FAILURE(status)) {
912 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
913 }
914 u_austrncpy(desta, dest, DESTCAPACITY);
915 if (strcmp(numFormatted, desta) != 0) {
916 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
917 __FILE__, __LINE__, numFormatted, desta);
918 }
919 if (strlen(numFormatted) != resultSize) {
920 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
921 __FILE__, __LINE__, strlen(numFormatted), resultSize);
922 }
923
924 /* Format with a FieldPosition parameter */
925
926 fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
927 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status);
928 if (U_FAILURE(status)) {
929 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
930 }
931 u_austrncpy(desta, dest, DESTCAPACITY);
932 if (strcmp(numFormatted, desta) != 0) {
933 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n",
934 __FILE__, __LINE__, numFormatted, desta);
935 }
936 if (fieldPos.beginIndex != 26) { /* index of "." in formatted number */
937 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
938 __FILE__, __LINE__, 0, fieldPos.beginIndex);
939 }
940 if (fieldPos.endIndex != 27) {
941 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n",
942 __FILE__, __LINE__, 0, fieldPos.endIndex);
943 }
944
945 /* Parse */
946
947 status = U_ZERO_ERROR;
948 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
949 resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status);
950 if (U_FAILURE(status)) {
951 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
952 }
953 if (uprv_strcmp(parseExpected, desta) != 0) {
954 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
955 __FILE__, __LINE__, parseExpected, desta);
956 } else {
957 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
958 __FILE__, __LINE__, desta);
959 }
960 if (strlen(parseExpected) != resultSize) {
961 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
962 __FILE__, __LINE__, strlen(parseExpected), resultSize);
963 }
964
965 /* Parse with a parsePos parameter */
966
967 status = U_ZERO_ERROR;
968 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */
969 parsePos = 3; /* 12,345,678,900,987,654,321.12345679 */
970 /* start parsing at the the third char */
971 resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status);
972 if (U_FAILURE(status)) {
973 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
974 }
975 if (strcmp(parseExpected2, desta) != 0) { /* "3.4567890098765432112345679E+17" */
976 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
977 __FILE__, __LINE__, parseExpected2, desta);
978 } else {
979 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
980 __FILE__, __LINE__, desta);
981 }
982 if (strlen(numFormatted) != parsePos) {
983 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
984 __FILE__, __LINE__, strlen(parseExpected), parsePos);
985 }
986
987 unum_close(fmt);
988 }
989
990 status = U_ZERO_ERROR;
991 /* Test invalid symbol argument */
992 {
993 int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1;
994 int32_t badsymbolSmall = -1;
995 UChar value[10];
996 int32_t valueLength = 10;
997 UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
998 if (U_FAILURE(status)) {
999 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
1000 } else {
1001 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status);
1002 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
1003
1004 status = U_ZERO_ERROR;
1005 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status);
1006 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
1007
1008 status = U_ZERO_ERROR;
1009 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status);
1010 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n");
1011
1012 status = U_ZERO_ERROR;
1013 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status);
1014 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n");
1015
1016 unum_close(fmt);
1017 }
1018 }
1019
1020
1021 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/
1022 unum_close(def);
1023 unum_close(fr);
1024 unum_close(cur_def);
1025 unum_close(cur_fr);
1026 unum_close(per_def);
1027 unum_close(per_fr);
1028 unum_close(spellout_def);
1029 unum_close(pattern);
1030 unum_close(cur_frpattern);
1031 unum_close(myclone);
1032
1033}
1034
1035static void TestParseZero(void)
1036{
1037 UErrorCode errorCode = U_ZERO_ERROR;
1038 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */
1039 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
1040 double dbl;
1041
1042#if 0
1043 UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode);
1044#else
1045 UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode);
1046#endif
1047
1048 dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode );
1049 if (U_FAILURE(errorCode)) {
1050 log_data_err("Result - %s\n", u_errorName(errorCode));
1051 } else {
1052 log_verbose("Double: %f\n", dbl);
1053 }
1054 unum_close(unum);
1055}
1056
1057static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */
1058static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */
1059static const UChar dollarsUS4Sym[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
1060static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */
1061static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */
1062static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */
1063static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */
1064static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */
1065static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */
1066static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */
1067static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/
1068static 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 */
1069static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/
1070static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/
1071
1072typedef struct {
1073 const char * locale;
1074 const char * descrip;
1075 const UChar * currStr;
1076 const UChar * plurStr;
1077 UErrorCode parsDoubExpectErr;
1078 int32_t parsDoubExpectPos;
1079 double parsDoubExpectVal;
1080 UErrorCode parsCurrExpectErr;
1081 int32_t parsCurrExpectPos;
1082 double parsCurrExpectVal;
1083 const char * parsCurrExpectCurr;
1084} ParseCurrencyItem;
1085
1086static const ParseCurrencyItem parseCurrencyItems[] = {
1087 { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" },
1088 { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" },
1089 { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1090 { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1091 { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1092 { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1093 { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1094
1095 { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" },
1096 { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" },
1097 { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1098 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1099 { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" },
1100 { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" },
1101 { "en_GB", "dollars4", dollarsUS4Sym,dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 4, 4.0, "USD" },
1102
1103 { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" },
1104 { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" },
1105 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 2, 0.0, U_PARSE_ERROR, 2, 0.0, "" },
1106 { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1107 { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
1108
1109 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL }
1110};
1111
1112static void TestParseCurrency()
1113{
1114 const ParseCurrencyItem * itemPtr;
1115 for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) {
1116 UNumberFormat* unum;
1117 UErrorCode status;
1118 double parseVal;
1119 int32_t parsePos;
1120 UChar parseCurr[4];
1121 char parseCurrB[4];
1122
1123 status = U_ZERO_ERROR;
1124 unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
1125 if (U_SUCCESS(status)) {
1126 const UChar * currStr = itemPtr->currStr;
1127 status = U_ZERO_ERROR;
1128 parsePos = 0;
1129 parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status);
1130 if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
1131 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
1132 itemPtr->locale, itemPtr->descrip,
1133 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
1134 u_errorName(status), parsePos, parseVal );
1135 }
1136 status = U_ZERO_ERROR;
1137 parsePos = 0;
1138 parseCurr[0] = 0;
1139 parseVal = unum_parseDoubleCurrency(unum, currStr, -1, &parsePos, parseCurr, &status);
1140 u_austrncpy(parseCurrB, parseCurr, 4);
1141 if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal ||
1142 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1143 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n",
1144 itemPtr->locale, itemPtr->descrip,
1145 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1146 u_errorName(status), parsePos, parseVal, parseCurrB );
1147 }
1148 unum_close(unum);
1149 } else {
1150 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1151 }
1152
1153 if (itemPtr->plurStr != NULL) {
1154 status = U_ZERO_ERROR;
1155 unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status);
1156 if (U_SUCCESS(status)) {
1157 status = U_ZERO_ERROR;
1158 parsePos = 0;
1159 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
1160 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
1161 log_err("UNUM_CURRENCY parseDouble Plural %s/%s, expect %s val %.1f, get %s val %.1f\n",
1162 itemPtr->locale, itemPtr->descrip,
1163 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
1164 u_errorName(status), parseVal );
1165 }
1166 status = U_ZERO_ERROR;
1167 parsePos = 0;
1168 parseCurr[0] = 0;
1169 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status);
1170 u_austrncpy(parseCurrB, parseCurr, 4);
1171 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal ||
1172 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) {
1173 log_err("UNUM_CURRENCY parseDoubleCurrency Plural %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
1174 itemPtr->locale, itemPtr->descrip,
1175 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr,
1176 u_errorName(status), parseVal, parseCurrB );
1177 }
1178 unum_close(unum);
1179 } else {
1180 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status));
1181 }
1182 }
1183 }
1184}
1185
1186typedef struct {
1187 const char * testname;
1188 const char * locale;
1189 UBool lenient;
1190 const UChar * source;
1191 int32_t startPos;
1192 int32_t value;
1193 int32_t endPos;
1194 UErrorCode status;
1195} NumParseTestItem;
1196
1197static const UChar ustr_zh50d[] = {0x4E94, 0x3007, 0}; /* decimal 50 */
1198static const UChar ustr_zh05a[] = {0x96F6, 0x4E94, 0}; /* decimal-alt 05 */
1199static const UChar ustr_zh05d[] = {0x3007, 0x4E94, 0}; /* decimal 05 */
1200
1201static const NumParseTestItem altnumParseTests[] = {
1202 /* name loc lenent src start val end status */
1203 { "zh@hd,50dL","zh@numbers=hanidec", TRUE, ustr_zh50d, 0, 50, 2, U_USING_DEFAULT_WARNING },
1204 { "zh@hd,05aL","zh@numbers=hanidec", TRUE, ustr_zh05a, 0, 5, 2, U_USING_DEFAULT_WARNING },
1205 { "zh@hd,05dL","zh@numbers=hanidec", TRUE, ustr_zh05d, 0, 5, 2, U_USING_DEFAULT_WARNING },
1206 { NULL, NULL, FALSE, NULL, 0, 0, 0, 0 } /* terminator */
1207};
1208
1209static void TestParseAltNum(void)
1210{
1211 const NumParseTestItem * testPtr;
1212 for (testPtr = altnumParseTests; testPtr->testname != NULL; ++testPtr) {
1213 UErrorCode status = U_ZERO_ERROR;
1214 int32_t value, position = testPtr->startPos;
1215 UNumberFormat *nf = unum_open(UNUM_DECIMAL, NULL, 0, testPtr->locale, NULL, &status);
1216 if (U_FAILURE(status)) {
1217 log_err_status(status, "unum_open fails for UNUM_DECIMAL with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1218 continue;
1219 }
1220 unum_setAttribute(nf, UNUM_LENIENT_PARSE, testPtr->lenient);
1221 value = unum_parse(nf, testPtr->source, -1, &position, &status);
1222 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1223 log_err("unum_parse DECIMAL, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1224 testPtr->locale, testPtr->testname, testPtr->startPos,
1225 testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1226 value, position, myErrorName(status) );
1227 }
1228 unum_close(nf);
1229 }
1230}
1231
1232static const UChar ustr_en0[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */
1233static const UChar ustr_123[] = {0x31, 0x32, 0x33, 0}; /* 123 */
1234static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64,
1235 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1236 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
1237static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d,
1238 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */
1239static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
1240static const UChar ustr_zh50s[] = {0x4E94, 0x5341, 0}; /* spellout 50 */
1241//static const UChar ustr_zh50d[] = [reuse from above] /* decimal 50 */
1242//static const UChar ustr_zh05a[] = [reuse from above] /* decimal-alt 05 */
1243//static const UChar ustr_zh05d[] = [reuse from above] /* decimal 05 */
1244
1245#define NUMERIC_STRINGS_NOT_PARSEABLE 1 // ticket/8224
1246
1247static const NumParseTestItem spelloutParseTests[] = {
1248 /* name loc lenent src start val end status */
1249 { "en0", "en", FALSE, ustr_en0, 0, 0, 4, U_ZERO_ERROR },
1250 { "en0", "en", FALSE, ustr_en0, 2, 0, 2, U_PARSE_ERROR },
1251 { "en0", "ja", FALSE, ustr_en0, 0, 0, 0, U_PARSE_ERROR },
1252#if NUMERIC_STRINGS_NOT_PARSEABLE
1253 { "123", "en", FALSE, ustr_123, 0, 0, 0, U_PARSE_ERROR },
1254#else
1255 { "123", "en", FALSE, ustr_123, 0, 123, 3, U_ZERO_ERROR },
1256#endif
1257 { "123L", "en", TRUE, ustr_123, 0, 123, 3, U_ZERO_ERROR },
1258 { "en123", "en", FALSE, ustr_en123, 0, 123, 24, U_ZERO_ERROR },
1259 { "en123", "en", FALSE, ustr_en123, 12, 23, 24, U_ZERO_ERROR },
1260 { "en123", "fr", FALSE, ustr_en123, 16, 0, 16, U_PARSE_ERROR },
1261 { "fr123", "fr", FALSE, ustr_fr123, 0, 123, 16, U_ZERO_ERROR },
1262 { "fr123", "fr", FALSE, ustr_fr123, 5, 23, 16, U_ZERO_ERROR },
1263 { "fr123", "en", FALSE, ustr_fr123, 0, 0, 0, U_PARSE_ERROR },
1264 { "ja123", "ja", FALSE, ustr_ja123, 0, 123, 4, U_ZERO_ERROR },
1265 { "ja123", "ja", FALSE, ustr_ja123, 1, 23, 4, U_ZERO_ERROR },
1266 { "ja123", "fr", FALSE, ustr_ja123, 0, 0, 0, U_PARSE_ERROR },
1267 { "zh,50s", "zh", FALSE, ustr_zh50s, 0, 50, 2, U_ZERO_ERROR },
1268 // from ICU50m2, NUMERIC_STRINGS_NOT_PARSEABLE no longer affects the next three
1269 { "zh@hd,50d", "zh@numbers=hanidec", FALSE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR },
1270 { "zh@hd,05a", "zh@numbers=hanidec", FALSE, ustr_zh05a, 0, 5, 2, U_ZERO_ERROR },
1271 { "zh@hd,05d", "zh@numbers=hanidec", FALSE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR },
1272 { "zh@hd,50dL","zh@numbers=hanidec", TRUE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR },
1273 { "zh@hd,05aL","zh@numbers=hanidec", TRUE, ustr_zh05a, 0, 5, 2, U_ZERO_ERROR },
1274 { "zh@hd,05dL","zh@numbers=hanidec", TRUE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR },
1275 { "zh,50dL","zh", TRUE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
1276 { "zh,05aL","zh", TRUE, ustr_zh05a, 0, 0, 1, U_ZERO_ERROR },
1277 { "zh,05dL","zh", TRUE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
1278 { NULL, NULL, FALSE, NULL, 0, 0, 0, 0 } /* terminator */
1279};
1280
1281static void TestSpelloutNumberParse()
1282{
1283 const NumParseTestItem * testPtr;
1284 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
1285 UErrorCode status = U_ZERO_ERROR;
1286 int32_t value, position = testPtr->startPos;
1287 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
1288 if (U_FAILURE(status)) {
1289 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
1290 continue;
1291 }
1292 unum_setAttribute(nf, UNUM_LENIENT_PARSE, testPtr->lenient);
1293 status = U_ZERO_ERROR;
1294 value = unum_parse(nf, testPtr->source, -1, &position, &status);
1295 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) {
1296 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n",
1297 testPtr->locale, testPtr->testname, testPtr->startPos,
1298 testPtr->value, testPtr->endPos, myErrorName(testPtr->status),
1299 value, position, myErrorName(status) );
1300 }
1301 unum_close(nf);
1302 }
1303}
1304
1305static void TestSignificantDigits()
1306{
1307 UChar temp[128];
1308 int32_t resultlengthneeded;
1309 int32_t resultlength;
1310 UErrorCode status = U_ZERO_ERROR;
1311 UChar *result = NULL;
1312 UNumberFormat* fmt;
1313 double d = 123456.789;
1314
1315 u_uastrcpy(temp, "###0.0#");
1316 fmt=unum_open(UNUM_IGNORE, temp, -1, "en", NULL, &status);
1317 if (U_FAILURE(status)) {
1318 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1319 return;
1320 }
1321 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1322 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6);
1323
1324 u_uastrcpy(temp, "123457");
1325 resultlength=0;
1326 resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status);
1327 if(status==U_BUFFER_OVERFLOW_ERROR)
1328 {
1329 status=U_ZERO_ERROR;
1330 resultlength=resultlengthneeded+1;
1331 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1332 unum_formatDouble(fmt, d, result, resultlength, NULL, &status);
1333 }
1334 if(U_FAILURE(status))
1335 {
1336 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1337 return;
1338 }
1339 if(u_strcmp(result, temp)==0)
1340 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
1341 else
1342 log_err("FAIL: Error in number formatting using unum_formatDouble()\n");
1343 free(result);
1344 unum_close(fmt);
1345}
1346
1347static void TestSigDigRounding()
1348{
1349 UErrorCode status = U_ZERO_ERROR;
1350 UChar expected[128];
1351 UChar result[128];
1352 char temp1[128];
1353 char temp2[128];
1354 UNumberFormat* fmt;
1355 double d = 123.4;
1356
1357 fmt=unum_open(UNUM_DECIMAL, NULL, 0, "en", NULL, &status);
1358 if (U_FAILURE(status)) {
1359 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
1360 return;
1361 }
1362 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE);
1363 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
1364 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2);
1365 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */
1366
1367 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP);
1368 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0);
1369
1370 (void)unum_formatDouble(fmt, d, result, UPRV_LENGTHOF(result), NULL, &status);
1371 if(U_FAILURE(status))
1372 {
1373 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status));
1374 return;
1375 }
1376
1377 u_uastrcpy(expected, "140");
1378 if(u_strcmp(result, expected)!=0)
1379 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) );
1380
1381 unum_close(fmt);
1382}
1383
1384static void TestNumberFormatPadding()
1385{
1386 UChar *result=NULL;
1387 UChar temp1[512];
1388 UChar temp2[512];
1389
1390 UErrorCode status=U_ZERO_ERROR;
1391 int32_t resultlength;
1392 int32_t resultlengthneeded;
1393 UNumberFormat *pattern;
1394 double d1;
1395 double d = -10456.37;
1396 UFieldPosition pos1;
1397 int32_t parsepos;
1398
1399 /* create a number format using unum_openPattern(....)*/
1400 log_verbose("\nTesting unum_openPattern() with padding\n");
1401 u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)");
1402 status=U_ZERO_ERROR;
1403 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status);
1404 if(U_SUCCESS(status))
1405 {
1406 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
1407 }
1408 else
1409 {
1410 unum_close(pattern);
1411 }
1412
1413/* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
1414 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
1415 u_uastrcpy(temp2, "*x#########,##0.0#;(#########,##0.0#)"); // equivalent (?) output pattern
1416 status=U_ZERO_ERROR;
1417 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
1418 if(U_FAILURE(status))
1419 {
1420 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
1421 }
1422 else {
1423 log_verbose("Pass: padding unum_openPattern() works fine\n");
1424
1425 /*test for unum_toPattern()*/
1426 log_verbose("\nTesting padding unum_toPattern()\n");
1427 resultlength=0;
1428 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status);
1429 if(status==U_BUFFER_OVERFLOW_ERROR)
1430 {
1431 status=U_ZERO_ERROR;
1432 resultlength=resultlengthneeded+1;
1433 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1434 unum_toPattern(pattern, FALSE, result, resultlength, &status);
1435 }
1436 if(U_FAILURE(status))
1437 {
1438 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status));
1439 }
1440 else
1441 {
1442 if(u_strncmp(result, temp2, resultlengthneeded)!=0) {
1443 log_err(
1444 "FAIL: Error in extracting the padding pattern using unum_toPattern(): %d: %s != %s\n",
1445 resultlengthneeded,
1446 austrdup(temp2),
1447 austrdup(result));
1448 } else {
1449 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
1450 }
1451 }
1452 free(result);
1453/* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1454 u_uastrcpy(temp1, "xxxxx(10,456.37)");
1455 resultlength=0;
1456 pos1.field = UNUM_FRACTION_FIELD;
1457 resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status);
1458 if(status==U_BUFFER_OVERFLOW_ERROR)
1459 {
1460 status=U_ZERO_ERROR;
1461 resultlength=resultlengthneeded+1;
1462 result=(UChar*)malloc(sizeof(UChar) * resultlength);
1463 unum_formatDouble(pattern, d, result, resultlength, NULL, &status);
1464 }
1465 if(U_FAILURE(status))
1466 {
1467 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status));
1468 }
1469 else
1470 {
1471 if(u_strcmp(result, temp1)==0)
1472 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n");
1473 else
1474 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
1475 if(pos1.beginIndex == 13 && pos1.endIndex == 15)
1476 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n");
1477 else
1478 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n",
1479 pos1.beginIndex, pos1.endIndex);
1480
1481
1482 /* Testing unum_parse() and unum_parseDouble() */
1483 log_verbose("\nTesting padding unum_parseDouble()\n");
1484 parsepos=0;
1485 d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status);
1486 if(U_FAILURE(status))
1487 {
1488 log_err("padding parse failed. The error is : %s\n", myErrorName(status));
1489 }
1490
1491 if(d1!=d)
1492 log_err("Fail: Error in padding parsing\n");
1493 else
1494 log_verbose("Pass: padding parsing successful\n");
1495free(result);
1496 }
1497 }
1498
1499 unum_close(pattern);
1500}
1501
1502static UBool
1503withinErr(double a, double b, double err) {
1504 return uprv_fabs(a - b) < uprv_fabs(a * err);
1505}
1506
1507static void TestInt64Format() {
1508 UChar temp1[512];
1509 UChar result[512];
1510 UNumberFormat *fmt;
1511 UErrorCode status = U_ZERO_ERROR;
1512 const double doubleInt64Max = (double)U_INT64_MAX;
1513 const double doubleInt64Min = (double)U_INT64_MIN;
1514 const double doubleBig = 10.0 * (double)U_INT64_MAX;
1515 int32_t val32;
1516 int64_t val64;
1517 double valDouble;
1518 int32_t parsepos;
1519
1520 /* create a number format using unum_openPattern(....) */
1521 log_verbose("\nTesting Int64Format\n");
1522 u_uastrcpy(temp1, "#.#E0");
1523 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), "en_US", NULL, &status);
1524 if(U_FAILURE(status)) {
1525 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
1526 } else {
1527 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20);
1528 unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status);
1529 if (U_FAILURE(status)) {
1530 log_err("error in unum_format(): %s\n", myErrorName(status));
1531 } else {
1532 log_verbose("format int64max: '%s'\n", result);
1533 parsepos = 0;
1534 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1535 if (status != U_INVALID_FORMAT_ERROR) {
1536 log_err("parse didn't report error: %s\n", myErrorName(status));
1537 } else if (val32 != INT32_MAX) {
1538 log_err("parse didn't pin return value, got: %d\n", val32);
1539 }
1540
1541 status = U_ZERO_ERROR;
1542 parsepos = 0;
1543 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1544 if (U_FAILURE(status)) {
1545 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1546 } else if (val64 != U_INT64_MAX) {
1547 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1548 }
1549
1550 status = U_ZERO_ERROR;
1551 parsepos = 0;
1552 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1553 if (U_FAILURE(status)) {
1554 log_err("parseDouble returned error: %s\n", myErrorName(status));
1555 } else if (valDouble != doubleInt64Max) {
1556 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1557 }
1558 }
1559
1560 unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status);
1561 if (U_FAILURE(status)) {
1562 log_err("error in unum_format(): %s\n", myErrorName(status));
1563 } else {
1564 log_verbose("format int64min: '%s'\n", result);
1565 parsepos = 0;
1566 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1567 if (status != U_INVALID_FORMAT_ERROR) {
1568 log_err("parse didn't report error: %s\n", myErrorName(status));
1569 } else if (val32 != INT32_MIN) {
1570 log_err("parse didn't pin return value, got: %d\n", val32);
1571 }
1572
1573 status = U_ZERO_ERROR;
1574 parsepos = 0;
1575 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1576 if (U_FAILURE(status)) {
1577 log_err("parseInt64 returned error: %s\n", myErrorName(status));
1578 } else if (val64 != U_INT64_MIN) {
1579 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1580 }
1581
1582 status = U_ZERO_ERROR;
1583 parsepos = 0;
1584 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1585 if (U_FAILURE(status)) {
1586 log_err("parseDouble returned error: %s\n", myErrorName(status));
1587 } else if (valDouble != doubleInt64Min) {
1588 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1589 }
1590 }
1591
1592 unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status);
1593 if (U_FAILURE(status)) {
1594 log_err("error in unum_format(): %s\n", myErrorName(status));
1595 } else {
1596 log_verbose("format doubleBig: '%s'\n", result);
1597 parsepos = 0;
1598 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status);
1599 if (status != U_INVALID_FORMAT_ERROR) {
1600 log_err("parse didn't report error: %s\n", myErrorName(status));
1601 } else if (val32 != INT32_MAX) {
1602 log_err("parse didn't pin return value, got: %d\n", val32);
1603 }
1604
1605 status = U_ZERO_ERROR;
1606 parsepos = 0;
1607 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status);
1608 if (status != U_INVALID_FORMAT_ERROR) {
1609 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status));
1610 } else if (val64 != U_INT64_MAX) {
1611 log_err("parseInt64 returned incorrect value, got: %ld\n", val64);
1612 }
1613
1614 status = U_ZERO_ERROR;
1615 parsepos = 0;
1616 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1617 if (U_FAILURE(status)) {
1618 log_err("parseDouble returned error: %s\n", myErrorName(status));
1619 } else if (!withinErr(valDouble, doubleBig, 1e-15)) {
1620 log_err("parseDouble returned incorrect value, got: %g\n", valDouble);
1621 }
1622 }
1623
1624 u_uastrcpy(result, "5.06e-27");
1625 parsepos = 0;
1626 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status);
1627 if (U_FAILURE(status)) {
1628 log_err("parseDouble() returned error: %s\n", myErrorName(status));
1629 } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) {
1630 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble);
1631 }
1632 }
1633 unum_close(fmt);
1634}
1635
1636
1637static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
1638 char temp[512];
1639 UChar buffer[512];
1640 int32_t BUFSIZE = UPRV_LENGTHOF(buffer);
1641 double vals[] = {
1642 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1643 };
1644 int i;
1645
1646 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
1647 UErrorCode status = U_ZERO_ERROR;
1648 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1649 if (U_FAILURE(status)) {
1650 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1651 } else {
1652 u_austrcpy(temp, buffer);
1653 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1654 }
1655 }
1656
1657 /* check APIs now */
1658 {
1659 UErrorCode status = U_ZERO_ERROR;
1660 UParseError perr;
1661 u_uastrcpy(buffer, "#,##0.0#");
1662 unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status);
1663 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1664 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status));
1665 }
1666 }
1667
1668 {
1669 int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1670 log_verbose("lenient: 0x%x\n", isLenient);
1671 if (isLenient != FALSE) {
1672 log_err("didn't expect lenient value: %d\n", isLenient);
1673 }
1674
1675 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE);
1676 isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE);
1677 if (isLenient != TRUE) {
1678 log_err("didn't expect lenient value after set: %d\n", isLenient);
1679 }
1680 }
1681
1682 {
1683 double val2;
1684 double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE);
1685 if (val != -1) {
1686 log_err("didn't expect double attribute\n");
1687 }
1688 val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1689 if ((val == -1) == isDecimal) {
1690 log_err("didn't expect -1 rounding increment\n");
1691 }
1692 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5);
1693 val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT);
1694 if (isDecimal && (val2 - val != .5)) {
1695 log_err("set rounding increment had no effect on decimal format");
1696 }
1697 }
1698
1699 {
1700 UErrorCode status = U_ZERO_ERROR;
1701 int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1702 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1703 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status));
1704 }
1705 if (U_SUCCESS(status)) {
1706 u_austrcpy(temp, buffer);
1707 log_verbose("default ruleset: '%s'\n", temp);
1708 }
1709
1710 status = U_ZERO_ERROR;
1711 len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status);
1712 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) {
1713 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status));
1714 }
1715 if (U_SUCCESS(status)) {
1716 u_austrcpy(temp, buffer);
1717 log_verbose("public rulesets: '%s'\n", temp);
1718
1719 /* set the default ruleset to the first one found, and retry */
1720
1721 if (len > 0) {
1722 for (i = 0; i < len && temp[i] != ';'; ++i){};
1723 if (i < len) {
1724 buffer[i] = 0;
1725 unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status);
1726 if (U_FAILURE(status)) {
1727 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status));
1728 } else {
1729 int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status);
1730 if (U_FAILURE(status)) {
1731 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status));
1732 } else if (len2 != i) {
1733 u_austrcpy(temp, buffer);
1734 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp);
1735 } else {
1736 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
1737 status = U_ZERO_ERROR;
1738 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status);
1739 if (U_FAILURE(status)) {
1740 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status));
1741 } else {
1742 u_austrcpy(temp, buffer);
1743 log_verbose("formatting %g returned '%s'\n", vals[i], temp);
1744 }
1745 }
1746 }
1747 }
1748 }
1749 }
1750 }
1751 }
1752
1753 {
1754 UErrorCode status = U_ZERO_ERROR;
1755 unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status);
1756 if (U_SUCCESS(status)) {
1757 u_austrcpy(temp, buffer);
1758 log_verbose("pattern: '%s'\n", temp);
1759 } else if (status != U_BUFFER_OVERFLOW_ERROR) {
1760 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status));
1761 } else {
1762 log_verbose("pattern too long to display\n");
1763 }
1764 }
1765
1766 {
1767 UErrorCode status = U_ZERO_ERROR;
1768 int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status);
1769 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1770 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status));
1771 }
1772
1773 unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status);
1774 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) {
1775 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status));
1776 }
1777 }
1778}
1779
1780static void TestNonExistentCurrency() {
1781 UNumberFormat *format;
1782 UErrorCode status = U_ZERO_ERROR;
1783 UChar currencySymbol[8];
1784 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
1785
1786 /* Get a non-existent currency and make sure it returns the correct currency code. */
1787 format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status);
1788 if (format == NULL || U_FAILURE(status)) {
1789 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status));
1790 }
1791 else {
1792 unum_getSymbol(format,
1793 UNUM_CURRENCY_SYMBOL,
1794 currencySymbol,
1795 UPRV_LENGTHOF(currencySymbol),
1796 &status);
1797 if (u_strcmp(currencySymbol, QQQ) != 0) {
1798 log_err("unum_open set the currency to QQQ\n");
1799 }
1800 }
1801 unum_close(format);
1802}
1803
1804static void TestRBNFFormat() {
1805 UErrorCode status;
1806 UParseError perr;
1807 UChar pat[1024];
1808 UChar tempUChars[512];
1809 UNumberFormat *formats[5];
1810 int COUNT = UPRV_LENGTHOF(formats);
1811 int i;
1812
1813 for (i = 0; i < COUNT; ++i) {
1814 formats[i] = 0;
1815 }
1816
1817 /* instantiation */
1818 status = U_ZERO_ERROR;
1819 u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)");
1820 formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status);
1821 if (U_FAILURE(status)) {
1822 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
1823 return;
1824 }
1825
1826 status = U_ZERO_ERROR;
1827 formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status);
1828 if (U_FAILURE(status)) {
1829 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1830 return;
1831 }
1832
1833 status = U_ZERO_ERROR;
1834 formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status);
1835 if (U_FAILURE(status)) {
1836 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
1837 return;
1838 }
1839
1840 status = U_ZERO_ERROR;
1841 formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status);
1842 if (U_FAILURE(status)) {
1843 log_err_status(status, "unable to open duration %s\n", u_errorName(status));
1844 return;
1845 }
1846
1847 status = U_ZERO_ERROR;
1848 u_uastrcpy(pat,
1849 "%standard:\n"
1850 "-x: minus >>;\n"
1851 "x.x: << point >>;\n"
1852 "zero; one; two; three; four; five; six; seven; eight; nine;\n"
1853 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n"
1854 "seventeen; eighteen; nineteen;\n"
1855 "20: twenty[->>];\n"
1856 "30: thirty[->>];\n"
1857 "40: forty[->>];\n"
1858 "50: fifty[->>];\n"
1859 "60: sixty[->>];\n"
1860 "70: seventy[->>];\n"
1861 "80: eighty[->>];\n"
1862 "90: ninety[->>];\n"
1863 "100: =#,##0=;\n");
1864 u_uastrcpy(tempUChars,
1865 "%simple:\n"
1866 "=%standard=;\n"
1867 "20: twenty[ and change];\n"
1868 "30: thirty[ and change];\n"
1869 "40: forty[ and change];\n"
1870 "50: fifty[ and change];\n"
1871 "60: sixty[ and change];\n"
1872 "70: seventy[ and change];\n"
1873 "80: eighty[ and change];\n"
1874 "90: ninety[ and change];\n"
1875 "100: =#,##0=;\n"
1876 "%bogus:\n"
1877 "0.x: tiny;\n"
1878 "x.x: << point something;\n"
1879 "=%standard=;\n"
1880 "20: some reasonable number;\n"
1881 "100: some substantial number;\n"
1882 "100,000,000: some huge number;\n");
1883 /* This is to get around some compiler warnings about char * string length. */
1884 u_strcat(pat, tempUChars);
1885 formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status);
1886 if (U_FAILURE(status)) {
1887 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
1888 }
1889 if (U_FAILURE(status)) {
1890 log_err_status(status, "Something failed with %s\n", u_errorName(status));
1891 return;
1892 }
1893
1894 for (i = 0; i < COUNT; ++i) {
1895 log_verbose("\n\ntesting format %d\n", i);
1896 test_fmt(formats[i], (UBool)(i == 0));
1897 }
1898
1899 #define FORMAT_BUF_CAPACITY 64
1900 {
1901 UChar fmtbuf[FORMAT_BUF_CAPACITY];
1902 int32_t len;
1903 double nanvalue = uprv_getNaN();
1904 status = U_ZERO_ERROR;
1905 len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1906 if (U_FAILURE(status)) {
1907 log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status));
1908 } else {
1909 UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */
1910 if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) {
1911 log_err("unum_formatDouble NAN produced wrong answer for en_US\n");
1912 }
1913 }
1914 }
1915
1916 for (i = 0; i < COUNT; ++i) {
1917 unum_close(formats[i]);
1918 }
1919}
1920
1921static void TestRBNFRounding() {
1922 UChar fmtbuf[FORMAT_BUF_CAPACITY];
1923 UChar expectedBuf[FORMAT_BUF_CAPACITY];
1924 int32_t len;
1925 UErrorCode status = U_ZERO_ERROR;
1926 UNumberFormat* fmt = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", NULL, &status);
1927 if (U_FAILURE(status)) {
1928 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1929 return;
1930 }
1931 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1932 U_ASSERT(len < FORMAT_BUF_CAPACITY);
1933 if (U_FAILURE(status)) {
1934 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
1935 }
1936 u_uastrcpy(expectedBuf, "ten point one two three four five six seven eight nine");
1937 if (u_strcmp(expectedBuf, fmtbuf) != 0) {
1938 log_err("Wrong result for unrounded value\n");
1939 }
1940 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 3);
1941 if (unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS) != 3) {
1942 log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS));
1943 }
1944 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_UNNECESSARY) {
1945 log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
1946 }
1947 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP);
1948 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_HALFUP) {
1949 log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
1950 }
1951 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
1952 U_ASSERT(len < FORMAT_BUF_CAPACITY);
1953 if (U_FAILURE(status)) {
1954 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
1955 }
1956 u_uastrcpy(expectedBuf, "ten point one two three");
1957 if (u_strcmp(expectedBuf, fmtbuf) != 0) {
1958 char temp[512];
1959 u_austrcpy(temp, fmtbuf);
1960 log_err("Wrong result for rounded value. Got: %s\n", temp);
1961 }
1962 unum_close(fmt);
1963}
1964
1965static void TestCurrencyRegression(void) {
1966/*
1967 I've found a case where unum_parseDoubleCurrency is not doing what I
1968expect. The value I pass in is $1234567890q123460000.00 and this
1969returns with a status of zero error & a parse pos of 22 (I would
1970expect a parse error at position 11).
1971
1972I stepped into DecimalFormat::subparse() and it looks like it parses
1973the first 10 digits and then stops parsing at the q but doesn't set an
1974error. Then later in DecimalFormat::parse() the value gets crammed
1975into a long (which greatly truncates the value).
1976
1977This is very problematic for me 'cause I try to remove chars that are
1978invalid but this allows my users to enter bad chars and truncates
1979their data!
1980*/
1981
1982 UChar buf[1024];
1983 UChar currency[8];
1984 char acurrency[16];
1985 double d;
1986 UNumberFormat *cur;
1987 int32_t pos;
1988 UErrorCode status = U_ZERO_ERROR;
1989 const int32_t expected = 11;
1990
1991 currency[0]=0;
1992 u_uastrcpy(buf, "$1234567890q643210000.00");
1993 cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status);
1994
1995 if(U_FAILURE(status)) {
1996 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
1997 return;
1998 }
1999
2000 status = U_ZERO_ERROR; /* so we can test it later. */
2001 pos = 0;
2002
2003 d = unum_parseDoubleCurrency(cur,
2004 buf,
2005 -1,
2006 &pos, /* 0 = start */
2007 currency,
2008 &status);
2009
2010 u_austrcpy(acurrency, currency);
2011
2012 if(U_FAILURE(status) || (pos != expected)) {
2013 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n",
2014 expected, d, u_errorName(status), pos, acurrency);
2015 } else {
2016 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency);
2017 }
2018
2019 unum_close(cur);
2020}
2021
2022static void TestTextAttributeCrash(void) {
2023 UChar ubuffer[64] = {0x0049,0x004E,0x0052,0};
2024 static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
2025 static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0};
2026 int32_t used;
2027 UErrorCode status = U_ZERO_ERROR;
2028 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
2029 if (U_FAILURE(status)) {
2030 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
2031 return;
2032 }
2033 unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status);
2034 /*
2035 * the usual negative prefix and suffix seem to be '($' and ')' at this point
2036 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here
2037 */
2038 used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status);
2039 unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status);
2040 if (U_FAILURE(status)) {
2041 log_err("FAILED 2\n"); exit(1);
2042 }
2043 log_verbose("attempting to format...\n");
2044 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
2045 if (U_FAILURE(status) || 64 < used) {
2046 log_err("Failed formatting %s\n", u_errorName(status));
2047 return;
2048 }
2049 if (u_strcmp(expectedNeg, ubuffer) == 0) {
2050 log_err("Didn't get expected negative result\n");
2051 }
2052 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
2053 if (U_FAILURE(status) || 64 < used) {
2054 log_err("Failed formatting %s\n", u_errorName(status));
2055 return;
2056 }
2057 if (u_strcmp(expectedPos, ubuffer) == 0) {
2058 log_err("Didn't get expected positive result\n");
2059 }
2060 unum_close(nf);
2061}
2062
2063static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
2064 UErrorCode status = U_ZERO_ERROR;
2065 UChar myString[20];
2066 char tmpbuf[200];
2067 double aNumber = -1.0;
2068 unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
2069 log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
2070 if(U_FAILURE(status)) {
2071 log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
2072 return;
2073 }
2074 aNumber = unum_parse(nf, myString, -1, NULL, &status);
2075 if(U_FAILURE(status)) {
2076 log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
2077 return;
2078 }
2079 if(uprv_fabs(aNumber-myNumber)>.001) {
2080 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
2081 } else {
2082 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
2083 }
2084}
2085
2086static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
2087 TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
2088 TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
2089}
2090
2091static void TestNBSPInPattern(void) {
2092 UErrorCode status = U_ZERO_ERROR;
2093 UNumberFormat* nf = NULL;
2094 const char *testcase;
2095
2096
2097 testcase="ar_AE UNUM_CURRENCY";
2098 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
2099 if(U_FAILURE(status) || nf == NULL) {
2100 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
2101 return;
2102 }
2103 TestNBSPPatternRT(testcase, nf);
2104
2105 /* if we don't have CLDR 1.6 data, bring out the problem anyways */
2106 {
2107#define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00"
2108 UChar pat[200];
2109 testcase = "ar_AE special pattern: " SPECIAL_PATTERN;
2110 u_unescape(SPECIAL_PATTERN, pat, UPRV_LENGTHOF(pat));
2111 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
2112 if(U_FAILURE(status)) {
2113 log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status));
2114 } else {
2115 TestNBSPPatternRT(testcase, nf);
2116 }
2117#undef SPECIAL_PATTERN
2118 }
2119 unum_close(nf); status = U_ZERO_ERROR;
2120
2121 testcase="ar_AE UNUM_DECIMAL";
2122 nf = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status);
2123 if(U_FAILURE(status)) {
2124 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
2125 }
2126 TestNBSPPatternRT(testcase, nf);
2127 unum_close(nf); status = U_ZERO_ERROR;
2128
2129 testcase="ar_AE UNUM_PERCENT";
2130 nf = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status);
2131 if(U_FAILURE(status)) {
2132 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status));
2133 }
2134 TestNBSPPatternRT(testcase, nf);
2135 unum_close(nf); status = U_ZERO_ERROR;
2136
2137
2138
2139}
2140static void TestCloneWithRBNF(void) {
2141 UChar pattern[1024];
2142 UChar pat2[512];
2143 UErrorCode status = U_ZERO_ERROR;
2144 UChar buffer[256];
2145 UChar buffer_cloned[256];
2146 char temp1[256];
2147 char temp2[256];
2148 UNumberFormat *pform_cloned;
2149 UNumberFormat *pform;
2150
2151 u_uastrcpy(pattern,
2152 "%main:\n"
2153 "0.x: >%%millis-only>;\n"
2154 "x.0: <%%duration<;\n"
2155 "x.x: <%%durationwithmillis<>%%millis-added>;\n"
2156 "-x: ->>;%%millis-only:\n"
2157 "1000: 00:00.<%%millis<;\n"
2158 "%%millis-added:\n"
2159 "1000: .<%%millis<;\n"
2160 "%%millis:\n"
2161 "0: =000=;\n"
2162 "%%duration:\n"
2163 "0: =%%seconds-only=;\n"
2164 "60: =%%min-sec=;\n"
2165 "3600: =%%hr-min-sec=;\n"
2166 "86400/86400: <%%ddaayyss<[, >>];\n"
2167 "%%durationwithmillis:\n"
2168 "0: =%%seconds-only=;\n"
2169 "60: =%%min-sec=;\n"
2170 "3600: =%%hr-min-sec=;\n"
2171 "86400/86400: <%%ddaayyss<, >>;\n");
2172 u_uastrcpy(pat2,
2173 "%%seconds-only:\n"
2174 "0: 0:00:=00=;\n"
2175 "%%min-sec:\n"
2176 "0: :=00=;\n"
2177 "0/60: 0:<00<>>;\n"
2178 "%%hr-min-sec:\n"
2179 "0: :=00=;\n"
2180 "60/60: <00<>>;\n"
2181 "3600/60: <0<:>>>;\n"
2182 "%%ddaayyss:\n"
2183 "0 days;\n"
2184 "1 day;\n"
2185 "=0= days;");
2186
2187 /* This is to get around some compiler warnings about char * string length. */
2188 u_strcat(pattern, pat2);
2189
2190 pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status);
2191 unum_formatDouble(pform, 3600, buffer, 256, NULL, &status);
2192
2193 pform_cloned = unum_clone(pform,&status);
2194 unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status);
2195
2196 unum_close(pform);
2197 unum_close(pform_cloned);
2198
2199 if (u_strcmp(buffer,buffer_cloned)) {
2200 log_data_err("Result from cloned formatter not identical to the original. Original: %s Cloned: %s - (Are you missing data?)",u_austrcpy(temp1, buffer),u_austrcpy(temp2,buffer_cloned));
2201 }
2202}
2203
2204
2205static void TestNoExponent(void) {
2206 UErrorCode status = U_ZERO_ERROR;
2207 UChar str[100];
2208 const char *cstr;
2209 UNumberFormat *fmt;
2210 int32_t pos;
2211 int32_t expect = 0;
2212 int32_t num;
2213
2214 fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status);
2215
2216 if(U_FAILURE(status) || fmt == NULL) {
2217 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status));
2218 return;
2219 }
2220
2221 cstr = "10E6";
2222 u_uastrcpy(str, cstr);
2223 expect = 10000000;
2224 pos = 0;
2225 num = unum_parse(fmt, str, -1, &pos, &status);
2226 ASSERT_TRUE(pos==4);
2227 if(U_FAILURE(status)) {
2228 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2229 } else if(expect!=num) {
2230 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2231 } else {
2232 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2233 }
2234
2235 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2236
2237 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2238 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2239
2240 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2241
2242 pos = 0;
2243 expect=10;
2244 num = unum_parse(fmt, str, -1, &pos, &status);
2245 if(num==10000000) {
2246 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr);
2247 } else if(num==expect) {
2248 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr);
2249 }
2250 ASSERT_TRUE(pos==2);
2251
2252 status = U_ZERO_ERROR;
2253
2254 unum_close(fmt);
2255
2256 /* ok, now try scientific */
2257 fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status);
2258 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status);
2259
2260 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0);
2261
2262 cstr = "10E6";
2263 u_uastrcpy(str, cstr);
2264 expect = 10000000;
2265 pos = 0;
2266 num = unum_parse(fmt, str, -1, &pos, &status);
2267 ASSERT_TRUE(pos==4);
2268 if(U_FAILURE(status)) {
2269 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2270 } else if(expect!=num) {
2271 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2272 } else {
2273 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2274 }
2275
2276 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */
2277 log_verbose("set UNUM_PARSE_NO_EXPONENT\n");
2278
2279 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1);
2280
2281 // A scientific formatter should parse the exponent even if UNUM_PARSE_NO_EXPONENT is set
2282 cstr = "10E6";
2283 u_uastrcpy(str, cstr);
2284 expect = 10000000;
2285 pos = 0;
2286 num = unum_parse(fmt, str, -1, &pos, &status);
2287 ASSERT_TRUE(pos==4);
2288 if(U_FAILURE(status)) {
2289 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr);
2290 } else if(expect!=num) {
2291 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr);
2292 } else {
2293 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr);
2294 }
2295
2296 unum_close(fmt);
2297}
2298
2299static void TestMaxInt(void) {
2300 UErrorCode status = U_ZERO_ERROR;
2301 UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */
2302 UChar result1[1024] = { 0 }, result2[1024] = { 0 };
2303 int32_t len1, len2;
2304 UChar expect[] = { 0x0039, 0x0037, 0 };
2305 UNumberFormat *fmt = unum_open(
2306 UNUM_PATTERN_DECIMAL, /* style */
2307 &pattern_hash[0], /* pattern */
2308 u_strlen(pattern_hash), /* patternLength */
2309 "en",
2310 0, /* parseErr */
2311 &status);
2312 if(U_FAILURE(status) || fmt == NULL) {
2313 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status));
2314 return;
2315 }
2316
2317 unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2);
2318
2319 status = U_ZERO_ERROR;
2320 /* #1 */
2321 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2322 result1[len1]=0;
2323 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2324 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2325 }
2326
2327 status = U_ZERO_ERROR;
2328 /* #2 */
2329 len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status);
2330 result2[len2]=0;
2331 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2332 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2333 }
2334
2335
2336
2337 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2338 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0);
2339
2340 unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1);
2341 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */
2342 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1);
2343
2344 status = U_ZERO_ERROR;
2345 /* max int digits still '2' */
2346 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status);
2347 ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR);
2348 status = U_ZERO_ERROR;
2349
2350 /* But, formatting 97->'97' works fine. */
2351
2352 /* #1 */
2353 len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status);
2354 result1[len1]=0;
2355 if(U_FAILURE(status) || u_strcmp(expect, result1)) {
2356 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status));
2357 }
2358
2359 status = U_ZERO_ERROR;
2360 /* #2 */
2361 len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status);
2362 result2[len2]=0;
2363 if(U_FAILURE(status) || u_strcmp(expect, result2)) {
2364 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status));
2365 }
2366
2367
2368 unum_close(fmt);
2369}
2370
2371static void TestSignAlwaysShown(void) {
2372 UErrorCode status = U_ZERO_ERROR;
2373 UNumberFormat *fmt = unum_open(
2374 UNUM_DECIMAL, /* style */
2375 NULL, /* pattern */
2376 0, /* patternLength */
2377 "en-US",
2378 NULL, /* parseErr */
2379 &status);
2380 assertSuccess("Creating UNumberFormat", &status);
2381 unum_setAttribute(fmt, UNUM_SIGN_ALWAYS_SHOWN, 1);
2382 UChar result[100];
2383 unum_formatDouble(fmt, 42, result, 100, NULL, &status);
2384 assertSuccess("Formatting with UNumberFormat", &status);
2385 assertUEquals("Result with sign always shown", u"+42", result);
2386 unum_close(fmt);
2387}
2388
2389static void TestMinimumGroupingDigits(void) {
2390 UErrorCode status = U_ZERO_ERROR;
2391 UNumberFormat *fmt = unum_open(
2392 UNUM_DECIMAL, /* style */
2393 NULL, /* pattern */
2394 0, /* patternLength */
2395 "en-US",
2396 NULL, /* parseErr */
2397 &status);
2398 assertSuccess("Creating UNumberFormat", &status);
2399 unum_setAttribute(fmt, UNUM_MINIMUM_GROUPING_DIGITS, 2);
2400 UChar result[100];
2401 unum_formatDouble(fmt, 1234, result, 100, NULL, &status);
2402 assertSuccess("Formatting with UNumberFormat A", &status);
2403 assertUEquals("Result with minimum grouping digits A", u"1234", result);
2404 unum_formatDouble(fmt, 12345, result, 100, NULL, &status);
2405 assertSuccess("Formatting with UNumberFormat B", &status);
2406 assertUEquals("Result with minimum grouping digits B", u"12,345", result);
2407 unum_close(fmt);
2408}
2409
2410static void TestParseCaseSensitive(void) {
2411 UErrorCode status = U_ZERO_ERROR;
2412 UNumberFormat *fmt = unum_open(
2413 UNUM_DECIMAL, /* style */
2414 NULL, /* pattern */
2415 0, /* patternLength */
2416 "en-US",
2417 NULL, /* parseErr */
2418 &status);
2419 assertSuccess("Creating UNumberFormat", &status);
2420 double result = unum_parseDouble(fmt, u"1e2", -1, NULL, &status);
2421 assertSuccess("Parsing with UNumberFormat, case insensitive", &status);
2422 assertIntEquals("Result with case sensitive", 100, (int64_t)result);
2423 unum_setAttribute(fmt, UNUM_PARSE_CASE_SENSITIVE, 1);
2424 int32_t ppos = 0;
2425 result = unum_parseDouble(fmt, u"1e2", -1, &ppos, &status);
2426 assertSuccess("Parsing with UNumberFormat, case sensitive", &status);
2427 assertIntEquals("Position with case sensitive", 1, ppos);
2428 assertIntEquals("Result with case sensitive", 1, (int64_t)result);
2429 unum_close(fmt);
2430}
2431
2432static void TestUFormattable(void) {
2433 UChar out2k[2048];
2434 // simple test for API docs
2435 {
2436 UErrorCode status = U_ZERO_ERROR;
2437 UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2438 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2439 //! [unum_parseToUFormattable]
2440 const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */
2441 int32_t result = 0;
2442 UFormattable *ufmt = ufmt_open(&status);
2443 unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status);
2444 if (ufmt_isNumeric(ufmt)) {
2445 result = ufmt_getLong(ufmt, &status); /* == 123 */
2446 } /* else { ... } */
2447 ufmt_close(ufmt);
2448 //! [unum_parseToUFormattable]
2449 assertTrue("result == 123", (result == 123));
2450 }
2451 unum_close(unum);
2452 }
2453 // test with explicitly created ufmt_open
2454 {
2455 UChar buffer[2048];
2456 UErrorCode status = U_ZERO_ERROR;
2457 UFormattable *ufmt;
2458 UNumberFormat *unum;
2459 const char *pattern = "";
2460
2461 ufmt = ufmt_open(&status);
2462 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2463 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) {
2464
2465 pattern = "31337";
2466 log_verbose("-- pattern: %s\n", pattern);
2467 u_uastrcpy(buffer, pattern);
2468 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2469 if(assertSuccess("unum_parseToUFormattable(31337)", &status)) {
2470 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337);
2471 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG);
2472 log_verbose("long = %d\n", ufmt_getLong(ufmt, &status));
2473 assertSuccess("ufmt_getLong()", &status);
2474 }
2475 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2476 if(assertSuccess("unum_formatUFormattable(31337)", &status)) {
2477 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2478 }
2479
2480 pattern = "3.14159";
2481 log_verbose("-- pattern: %s\n", pattern);
2482 u_uastrcpy(buffer, pattern);
2483 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status);
2484 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) {
2485 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15));
2486 assertSuccess("ufmt_getDouble()", &status);
2487 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE);
2488 log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status));
2489 }
2490 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2491 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2492 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2493 }
2494 }
2495 ufmt_close(ufmt);
2496 unum_close(unum);
2497 }
2498
2499 // test with auto-generated ufmt
2500 {
2501 UChar buffer[2048];
2502 UErrorCode status = U_ZERO_ERROR;
2503 UFormattable *ufmt = NULL;
2504 UNumberFormat *unum;
2505 const char *pattern = "73476730924573500000000"; // weight of the moon, kg
2506
2507 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern);
2508 u_uastrcpy(buffer, pattern);
2509
2510 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status);
2511 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) {
2512
2513 ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */
2514 buffer, -1, NULL, &status);
2515 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) {
2516 log_verbose("new formattable allocated at %p\n", (void*)ufmt);
2517 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt));
2518 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status);
2519 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) {
2520 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k));
2521 }
2522
2523 log_verbose("double: %g\n", ufmt_getDouble(ufmt, &status));
2524 assertSuccess("ufmt_getDouble()", &status);
2525
2526 log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status));
2527 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status));
2528 // status is now a failure due to ufmt_getLong() above.
2529 // the intltest does extensive r/t testing of Formattable vs. UFormattable.
2530 }
2531 }
2532
2533 unum_close(unum);
2534 ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable()
2535 }
2536}
2537
2538typedef struct {
2539 const char* locale;
2540 const char* numsys;
2541 int32_t radix;
2542 UBool isAlgorithmic;
2543 const UChar* description;
2544} NumSysTestItem;
2545
2546
2547static const UChar latnDesc[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789
2548static const UChar romanDesc[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper
2549static const UChar arabDesc[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; //
2550static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; //
2551static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; //
2552static const UChar hantDesc[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,
2553 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D,
2554 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal
2555
2556static const NumSysTestItem numSysTestItems[] = {
2557 //locale numsys radix isAlgo description
2558 { "en", "latn", 10, FALSE, latnDesc },
2559 { "en@numbers=roman", "roman", 10, TRUE, romanDesc },
2560 { "en@numbers=finance", "latn", 10, FALSE, latnDesc },
2561 { "ar-EG", "arab", 10, FALSE, arabDesc },
2562 { "fa", "arabext", 10, FALSE, arabextDesc },
2563 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE, hanidecDesc },
2564 { "zh_Hant@numbers=traditional", "hant", 10, TRUE, hantDesc },
2565 { NULL, NULL, 0, FALSE, NULL },
2566};
2567enum { kNumSysDescripBufMax = 64 };
2568
2569static void TestUNumberingSystem(void) {
2570 const NumSysTestItem * itemPtr;
2571 UNumberingSystem * unumsys;
2572 UEnumeration * uenum;
2573 const char * numsys;
2574 UErrorCode status;
2575
2576 for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) {
2577 status = U_ZERO_ERROR;
2578 unumsys = unumsys_open(itemPtr->locale, &status);
2579 if ( U_SUCCESS(status) ) {
2580 UChar ubuf[kNumSysDescripBufMax];
2581 int32_t ulen, radix = unumsys_getRadix(unumsys);
2582 UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys);
2583 numsys = unumsys_getName(unumsys);
2584 if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) {
2585 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n",
2586 itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic);
2587 }
2588 ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status);
2589 (void)ulen; // Suppress variable not used warning.
2590 if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) {
2591 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status));
2592 }
2593 unumsys_close(unumsys);
2594 } else {
2595 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status));
2596 }
2597 }
2598
2599 for (int i=0; i<3; ++i) {
2600 // Run the test of unumsys_openAvailableNames() multiple times.
2601 // Helps verify the management of the internal cache of the names.
2602 status = U_ZERO_ERROR;
2603 uenum = unumsys_openAvailableNames(&status);
2604 if ( U_SUCCESS(status) ) {
2605 int32_t numsysCount = 0;
2606 // sanity check for a couple of number systems that must be in the enumeration
2607 UBool foundLatn = FALSE;
2608 UBool foundArab = FALSE;
2609 while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
2610 status = U_ZERO_ERROR;
2611 unumsys = unumsys_openByName(numsys, &status);
2612 if ( U_SUCCESS(status) ) {
2613 numsysCount++;
2614 if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
2615 if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
2616 unumsys_close(unumsys);
2617 } else {
2618 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
2619 numsys, myErrorName(status));
2620 }
2621 }
2622 uenum_close(uenum);
2623 if ( numsysCount < 40 || !foundLatn || !foundArab ) {
2624 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
2625 numsysCount, foundLatn, foundArab);
2626 }
2627 } else {
2628 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
2629 }
2630 }
2631}
2632
2633/* plain-C version of test in numfmtst.cpp */
2634enum { kUBufMax = 64, kBBufMax = 128 };
2635static void TestCurrencyIsoPluralFormat(void) {
2636 static const char* DATA[][8] = {
2637 // the data are:
2638 // locale,
2639 // currency amount to be formatted,
2640 // currency ISO code to be formatted,
2641 // format result using CURRENCYSTYLE,
2642 // format result using CURRENCY_STANDARD,
2643 // format result using CURRENCY_ACCOUNTING,
2644 // format result using ISOCURRENCYSTYLE,
2645 // format result using PLURALCURRENCYSTYLE,
2646
2647 // locale amount ISOcode CURRENCYSTYLE CURRENCY_STANDARD CURRENCY_ACCOUNTING ISOCURRENCYSTYLE PLURALCURRENCYSTYLE
2648 {"en_US", "1", "USD", "$1.00", "$1.00", "$1.00", "USD\\u00A01.00", "1.00 US dollars"},
2649 {"en_US", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD\\u00A01,234.56", "1,234.56 US dollars"},
2650 {"en_US@cf=account", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD\\u00A01,234.56", "1,234.56 US dollars"},
2651 {"en_US", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2652 {"en_US@cf=account", "-1234.56", "USD", "($1,234.56)", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2653 {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
2654 {"zh_CN", "1", "USD", "US$1.00", "US$1.00", "US$1.00", "USD\\u00A01.00", "1.00\\u00A0\\u7F8E\\u5143"},
2655 {"zh_CN", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2656 {"zh_CN@cf=account", "-1", "USD", "(US$1.00)", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2657 {"zh_CN@cf=standard", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD\\u00A01.00", "-1.00\\u00A0\\u7F8E\\u5143"},
2658 {"zh_CN", "1234.56", "USD", "US$1,234.56", "US$1,234.56", "US$1,234.56", "USD\\u00A01,234.56", "1,234.56\\u00A0\\u7F8E\\u5143"},
2659 // {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "CHY1.00", "CHY1.00", "1.00 CHY"}, // wrong ISO code
2660 // {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, // wrong ISO code
2661 {"zh_CN", "1", "CNY", "\\u00A51.00", "\\u00A51.00", "\\u00A51.00", "CNY\\u00A01.00", "1.00\\u00A0\\u4EBA\\u6C11\\u5E01"},
2662 {"zh_CN", "1234.56", "CNY", "\\u00A51,234.56", "\\u00A51,234.56", "\\u00A51,234.56", "CNY\\u00A01,234.56", "1,234.56\\u00A0\\u4EBA\\u6C11\\u5E01"},
2663 {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2664 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2665 {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2666 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2667 {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E "
2668 "\\u0440\\u0443\\u0431\\u043B\\u044F"},
2669 {"ja_JP", "42", NULL, "\\u00A542", "\\u00A542", "\\u00A542", "JPY\\u00A042", "42\\u00A0\\u5186"},
2670 {"ja_JP@currency=USD", "42", NULL, "$42.00", "$42.00", "$42.00", "USD\\u00A042.00", "42.00\\u00A0\\u7C73\\u30C9\\u30EB"},
2671 {"ms_MY", "1234.56", "MYR", "RM1,234.56", "RM1,234.56", "RM1,234.56", "MYR1,234.56", "1,234.56 Ringgit Malaysia"},
2672 {"id_ID", "1234.56", "IDR", "Rp1.235", "Rp1.235", "Rp1.235", "IDR\\u00A01.235", "1.235 Rupiah Indonesia"},
2673 // test locale without currency information
2674 {"root", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2675 {"root@cf=account", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
2676 // test choice format
2677 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
2678 };
2679 static const UNumberFormatStyle currencyStyles[] = {
2680 UNUM_CURRENCY,
2681 UNUM_CURRENCY_STANDARD,
2682 UNUM_CURRENCY_ACCOUNTING,
2683 UNUM_CURRENCY_ISO,
2684 UNUM_CURRENCY_PLURAL
2685 };
2686
2687 int32_t i, sIndex;
2688
2689 for (i=0; i<UPRV_LENGTHOF(DATA); ++i) {
2690 const char* localeString = DATA[i][0];
2691 double numberToBeFormat = atof(DATA[i][1]);
2692 const char* currencyISOCode = DATA[i][2];
2693 for (sIndex = 0; sIndex < UPRV_LENGTHOF(currencyStyles); ++sIndex) {
2694 UNumberFormatStyle style = currencyStyles[sIndex];
2695 UErrorCode status = U_ZERO_ERROR;
2696 UChar currencyCode[4] = {0};
2697 UChar ubufResult[kUBufMax];
2698 UChar ubufExpected[kUBufMax];
2699 int32_t ulenRes;
2700 const char* currencyISOCodeForLog = currencyISOCode;
2701
2702 UNumberFormat* unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
2703 if (U_FAILURE(status)) {
2704 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString, (int)style, myErrorName(status));
2705 continue;
2706 }
2707 if (currencyISOCode != NULL) {
2708 u_charsToUChars(currencyISOCode, currencyCode, 4);
2709 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
2710 } else {
2711 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, NULL, 0, &status);
2712 currencyISOCodeForLog = "(null)";
2713 }
2714 if (U_FAILURE(status)) {
2715 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString, currencyISOCodeForLog, myErrorName(status));
2716 }
2717 ulenRes = unum_formatDouble(unumFmt, numberToBeFormat, ubufResult, kUBufMax, NULL, &status);
2718 if (U_FAILURE(status)) {
2719 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString, currencyISOCodeForLog, myErrorName(status));
2720 } else {
2721 int32_t ulenExp = u_unescape(DATA[i][3 + sIndex], ubufExpected, kUBufMax);
2722 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
2723 char bbufExpected[kBBufMax];
2724 char bbufResult[kBBufMax];
2725 u_strToUTF8(bbufExpected, kBBufMax, NULL, ubufExpected, ulenExp, &status);
2726 u_strToUTF8(bbufResult, kBBufMax, NULL, ubufResult, ulenRes, &status);
2727 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got %s\n",
2728 localeString, currencyISOCodeForLog, bbufExpected, bbufResult);
2729 }
2730 }
2731 unum_close(unumFmt);
2732 }
2733 }
2734}
2735
2736typedef struct {
2737 const char * locale;
2738 UNumberFormatStyle style;
2739 UDisplayContext context;
2740 const char * expectedResult;
2741} TestContextItem;
2742
2743/* currently no locales have contextTransforms data for "symbol" type */
2744static const TestContextItem tcItems[] = { /* results for 123.45 */
2745 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2746 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2747 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2748 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
2749 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "one hundred twenty-three point four five" },
2750 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "One hundred twenty-three point four five" },
2751 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "One hundred twenty-three point four five" },
2752 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "One hundred twenty-three point four five" },
2753 { NULL, (UNumberFormatStyle)0, (UDisplayContext)0, NULL }
2754};
2755
2756static void TestContext(void) {
2757 UErrorCode status = U_ZERO_ERROR;
2758 const TestContextItem* itemPtr;
2759
2760 UNumberFormat *unum = unum_open(UNUM_SPELLOUT, NULL, 0, "en", NULL, &status);
2761 if ( U_SUCCESS(status) ) {
2762 UDisplayContext context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
2763 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_NONE) {
2764 log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n");
2765 status = U_ZERO_ERROR;
2766 }
2767 unum_setContext(unum, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
2768 context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
2769 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
2770 log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n");
2771 }
2772 unum_close(unum);
2773 } else {
2774 log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status));
2775 }
2776#if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION
2777 for (itemPtr = tcItems; itemPtr->locale != NULL; itemPtr++) {
2778 UChar ubufResult[kUBufMax];
2779 int32_t ulenRes;
2780
2781 status = U_ZERO_ERROR;
2782 unum = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
2783 if (U_FAILURE(status)) {
2784 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2785 itemPtr->locale, (int)itemPtr->style, myErrorName(status));
2786 continue;
2787 }
2788 unum_setContext(unum, itemPtr->context, &status);
2789 ulenRes = unum_formatDouble(unum, 123.45, ubufResult, kUBufMax, NULL, &status);
2790 if (U_FAILURE(status)) {
2791 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
2792 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, myErrorName(status));
2793 } else {
2794 UChar ubufExpected[kUBufMax];
2795 int32_t ulenExp = u_unescape(itemPtr->expectedResult, ubufExpected, kUBufMax);
2796 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
2797 char bbuf[kUBufMax*2];
2798 u_austrncpy(bbuf, ubufResult, sizeof(bbuf));
2799 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
2800 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, ulenExp,
2801 itemPtr->expectedResult, ulenRes, bbuf);
2802 }
2803 }
2804 unum_close(unum);
2805 }
2806#endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */
2807}
2808
2809static void TestCurrencyUsage(void) {
2810 static const char* DATA[][2] = {
2811 /* the data are:
2812 * currency ISO code to be formatted,
2813 * format result using CURRENCYSTYLE with CASH purpose,-
2814 * Note that as of CLDR 26:-
2815 * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
2816 * - CAD rounds to .05
2817 */
2818
2819 {"PKR", "PKR\\u00A0124"},
2820 {"CAD", "CA$123.55"},
2821 {"USD", "$123.57"}
2822 };
2823
2824 // 1st time for getter/setter, 2nd for factory method
2825 int32_t i;
2826 for(i=0; i<2; i++){
2827 const char* localeString = "en_US";
2828 double numberToBeFormat = 123.567;
2829 UNumberFormat* unumFmt;
2830 UNumberFormatStyle style = UNUM_CURRENCY;
2831 UErrorCode status = U_ZERO_ERROR;
2832 int32_t j;
2833
2834 if(i == 1){ // change for factory method
2835 style = UNUM_CASH_CURRENCY;
2836 }
2837
2838 unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status);
2839 if (U_FAILURE(status)) {
2840 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
2841 localeString, (int)style, myErrorName(status));
2842 continue;
2843 }
2844
2845 if(i == 0){ // this is for the getter/setter
2846 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_STANDARD) {
2847 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n");
2848 }
2849
2850 unum_setAttribute(unumFmt, UNUM_CURRENCY_USAGE, UCURR_USAGE_CASH);
2851 }
2852
2853 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_CASH) {
2854 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n");
2855 }
2856
2857 for (j=0; j<UPRV_LENGTHOF(DATA); ++j) {
2858 UChar expect[64];
2859 int32_t expectLen;
2860 UChar currencyCode[4];
2861 UChar result[64];
2862 int32_t resultLen;
2863 UFieldPosition pos = {0};
2864
2865 u_charsToUChars(DATA[j][0], currencyCode, 3);
2866 expectLen = u_unescape(DATA[j][1], expect, UPRV_LENGTHOF(expect));
2867
2868 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
2869 assertSuccess("num_setTextAttribute()", &status);
2870
2871 resultLen = unum_formatDouble(unumFmt, numberToBeFormat, result, UPRV_LENGTHOF(result),
2872 &pos, &status);
2873 assertSuccess("num_formatDouble()", &status);
2874
2875 if(resultLen != expectLen || u_strcmp(result, expect) != 0) {
2876 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n",
2877 aescstrdup(expect, expectLen), aescstrdup(result, resultLen));
2878 }
2879
2880 }
2881
2882 unum_close(unumFmt);
2883 }
2884}
2885
2886static UChar currFmtNegSameAsPos[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */
2887 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2888
2889// NOTE: As of ICU 62, identical positive and negative subpatterns means no minus sign!
2890// See CLDR ticket https://unicode.org/cldr/trac/ticket/10703
2891//static UChar currFmtToPatExpected[] = /* "\u00A4#,##0.00" */
2892// {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0};
2893static const UChar* currFmtToPatExpected = currFmtNegSameAsPos;
2894
2895static UChar currFmtResultExpected[] = /* "$100.00" */
2896 {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0};
2897
2898static UChar emptyString[] = {0};
2899
2900enum { kUBufSize = 64, kBBufSize = 128 };
2901
2902static void TestCurrFmtNegSameAsPositive(void) {
2903 UErrorCode status = U_ZERO_ERROR;
2904 UNumberFormat* unumfmt = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
2905 if ( U_SUCCESS(status) ) {
2906 unum_applyPattern(unumfmt, FALSE, currFmtNegSameAsPos, -1, NULL, &status);
2907 if (U_SUCCESS(status)) {
2908 UChar ubuf[kUBufSize];
2909 int32_t ulen = unum_toPattern(unumfmt, FALSE, ubuf, kUBufSize, &status);
2910 if (U_FAILURE(status)) {
2911 log_err("unum_toPattern fails with status %s\n", myErrorName(status));
2912 } else if (u_strcmp(ubuf, currFmtToPatExpected) != 0) {
2913 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected,-1), aescstrdup(ubuf,ulen));
2914 }
2915 unum_setSymbol(unumfmt, UNUM_MINUS_SIGN_SYMBOL, emptyString, 0, &status);
2916 if (U_SUCCESS(status)) {
2917 ulen = unum_formatDouble(unumfmt, -100.0, ubuf, kUBufSize, NULL, &status);
2918 if (U_FAILURE(status)) {
2919 log_err("unum_formatDouble fails with status %s\n", myErrorName(status));
2920 } else if (u_strcmp(ubuf, currFmtResultExpected) != 0) {
2921 log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected,-1), aescstrdup(ubuf,ulen));
2922 }
2923 } else {
2924 log_err("unum_setSymbol fails with status %s\n", myErrorName(status));
2925 }
2926 } else {
2927 log_err("unum_applyPattern fails with status %s\n", myErrorName(status));
2928 }
2929 unum_close(unumfmt);
2930 } else {
2931 log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status));
2932 }
2933}
2934
2935
2936typedef struct {
2937 double value;
2938 const char *valueStr;
2939 const char *expected;
2940} ValueAndExpectedString;
2941
2942static const ValueAndExpectedString enDecMinFrac[] = {
2943 {0.0, "0.0", "0.0"},
2944 {0.17, "0.17", "0.17"},
2945 {1.0, "1.0", "1.0"},
2946 {1234.0, "1234.0", "1,234.0"},
2947 {12345.0, "12345.0", "12,345.0"},
2948 {123456.0, "123456.0", "123,456.0"},
2949 {1234567.0, "1234567.0", "1,234,567.0"},
2950 {12345678.0, "12345678.0", "12,345,678.0"},
2951 {0.0, NULL, NULL}
2952};
2953static const ValueAndExpectedString enShort[] = {
2954 {0.0, "0.0", "0"},
2955 {0.17, "0.17", "0.17"},
2956 {1.0, "1.0", "1"},
2957 {1234.0, "1234.0", "1.2K"},
2958 {12345.0, "12345.0", "12K"},
2959 {123456.0, "123456.0", "123K"},
2960 {1234567.0, "1234567.0", "1.2M"},
2961 {12345678.0, "12345678.0", "12M"},
2962 {123456789.0, "123456789.0", "123M"},
2963 {1.23456789E9, "1.23456789E9", "1.2B"},
2964 {1.23456789E10, "1.23456789E10", "12B"},
2965 {1.23456789E11, "1.23456789E11", "123B"},
2966 {1.23456789E12, "1.23456789E12", "1.2T"},
2967 {1.23456789E13, "1.23456789E13", "12T"},
2968 {1.23456789E14, "1.23456789E14", "123T"},
2969 {1.23456789E15, "1.23456789E15", "1235T"},
2970 {0.0, NULL, NULL}
2971};
2972
2973static const ValueAndExpectedString enShortMax2[] = {
2974 {0.0, "0.0", "0"},
2975 {0.17, "0.17", "0.17"},
2976 {1.0, "1.0", "1"},
2977 {1234.0, "1234.0", "1.2K"},
2978 {12345.0, "12345.0", "12K"},
2979 {123456.0, "123456.0", "120K"},
2980 {1234567.0, "1234567.0", "1.2M"},
2981 {12345678.0, "12345678.0", "12M"},
2982 {123456789.0, "123456789.0", "120M"},
2983 {1.23456789E9, "1.23456789E9", "1.2B"},
2984 {1.23456789E10, "1.23456789E10", "12B"},
2985 {1.23456789E11, "1.23456789E11", "120B"},
2986 {1.23456789E12, "1.23456789E12", "1.2T"},
2987 {1.23456789E13, "1.23456789E13", "12T"},
2988 {1.23456789E14, "1.23456789E14", "120T"},
2989 {1.23456789E15, "1.23456789E15", "1200T"},
2990 {0.0, NULL, NULL}
2991};
2992
2993static const ValueAndExpectedString enShortMax5[] = {
2994 {0.0, "0.0", "0"},
2995 {0.17, "0.17", "0.17"},
2996 {1.0, "1.0", "1"},
2997 {1234.0, "1234.0", "1.234K"},
2998 {12345.0, "12345.0", "12.345K"},
2999 {123456.0, "123456.0", "123.46K"},
3000 {1234567.0, "1234567.0", "1.2346M"},
3001 {12345678.0, "12345678.0", "12.346M"},
3002 {123456789.0, "123456789.0", "123.46M"},
3003 {1.23456789E9, "1.23456789E9", "1.2346B"},
3004 {1.23456789E10, "1.23456789E10", "12.346B"},
3005 {1.23456789E11, "1.23456789E11", "123.46B"},
3006 {1.23456789E12, "1.23456789E12", "1.2346T"},
3007 {1.23456789E13, "1.23456789E13", "12.346T"},
3008 {1.23456789E14, "1.23456789E14", "123.46T"},
3009 {1.23456789E15, "1.23456789E15", "1234.6T"},
3010 {0.0, NULL, NULL}
3011};
3012
3013static const ValueAndExpectedString enShortMin3[] = {
3014 {0.0, "0.0", "0.00"},
3015 {0.17, "0.17", "0.170"},
3016 {1.0, "1.0", "1.00"},
3017 {1234.0, "1234.0", "1.23K"},
3018 {12345.0, "12345.0", "12.3K"},
3019 {123456.0, "123456.0", "123K"},
3020 {1234567.0, "1234567.0", "1.23M"},
3021 {12345678.0, "12345678.0", "12.3M"},
3022 {123456789.0, "123456789.0", "123M"},
3023 {1.23456789E9, "1.23456789E9", "1.23B"},
3024 {1.23456789E10, "1.23456789E10", "12.3B"},
3025 {1.23456789E11, "1.23456789E11", "123B"},
3026 {1.23456789E12, "1.23456789E12", "1.23T"},
3027 {1.23456789E13, "1.23456789E13", "12.3T"},
3028 {1.23456789E14, "1.23456789E14", "123T"},
3029 {1.23456789E15, "1.23456789E15", "1230T"},
3030 {0.0, NULL, NULL}
3031};
3032
3033static const ValueAndExpectedString jaShortMax2[] = {
3034 {1234.0, "1234.0", "1200"},
3035 {12345.0, "12345.0", "1.2\\u4E07"},
3036 {123456.0, "123456.0", "12\\u4E07"},
3037 {1234567.0, "1234567.0", "120\\u4E07"},
3038 {12345678.0, "12345678.0", "1200\\u4E07"},
3039 {123456789.0, "123456789.0", "1.2\\u5104"},
3040 {1.23456789E9, "1.23456789E9", "12\\u5104"},
3041 {1.23456789E10, "1.23456789E10", "120\\u5104"},
3042 {1.23456789E11, "1.23456789E11", "1200\\u5104"},
3043 {1.23456789E12, "1.23456789E12", "1.2\\u5146"},
3044 {1.23456789E13, "1.23456789E13", "12\\u5146"},
3045 {1.23456789E14, "1.23456789E14", "120\\u5146"},
3046 {0.0, NULL, NULL}
3047};
3048
3049static const ValueAndExpectedString srLongMax2[] = {
3050 {1234.0, "1234.0", "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
3051 {12345.0, "12345.0", "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
3052 {21789.0, "21789.0", "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
3053 {123456.0, "123456.0", "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
3054 {999999.0, "999999.0", "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
3055 {1234567.0, "1234567.0", "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
3056 {12345678.0, "12345678.0", "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
3057 {123456789.0, "123456789.0", "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
3058 {1.23456789E9, "1.23456789E9", "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
3059 {1.23456789E10, "1.23456789E10", "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
3060 {2.08901234E10, "2.08901234E10", "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
3061 {2.18901234E10, "2.18901234E10", "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
3062 {1.23456789E11, "1.23456789E11", "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
3063 {-1234.0, "-1234.0", "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
3064 {-12345.0, "-12345.0", "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
3065 {-21789.0, "-21789.0", "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
3066 {-123456.0, "-123456.0", "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
3067 {-999999.0, "-999999.0", "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
3068 {-1234567.0, "-1234567.0", "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3069 {-12345678.0, "-12345678.0", "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3070 {-123456789.0, "-123456789.0", "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
3071 {-1.23456789E9, "-1.23456789E9", "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
3072 {-1.23456789E10, "-1.23456789E10", "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
3073 {-2.08901234E10, "-2.08901234E10", "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
3074 {-2.18901234E10, "-2.18901234E10", "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
3075 {-1.23456789E11, "-1.23456789E11", "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
3076 {0.0, NULL, NULL}
3077};
3078
3079typedef struct {
3080 const char * locale;
3081 UNumberFormatStyle style;
3082 int32_t attribute; // UNumberFormatAttribute, or -1 for none
3083 int32_t attrValue; //
3084 const ValueAndExpectedString * veItems;
3085} LocStyleAttributeTest;
3086
3087static const LocStyleAttributeTest lsaTests[] = {
3088 { "en", UNUM_DECIMAL, UNUM_MIN_FRACTION_DIGITS, 1, enDecMinFrac },
3089 { "en", UNUM_DECIMAL_COMPACT_SHORT, -1, 0, enShort },
3090 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, enShortMax2 },
3091 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 5, enShortMax5 },
3092 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MIN_SIGNIFICANT_DIGITS, 3, enShortMin3 },
3093 { "ja", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, jaShortMax2 },
3094 { "sr", UNUM_DECIMAL_COMPACT_LONG, UNUM_MAX_SIGNIFICANT_DIGITS, 2, srLongMax2 },
3095 { NULL, (UNumberFormatStyle)0, -1, 0, NULL }
3096};
3097
3098static void TestVariousStylesAndAttributes(void) {
3099 const LocStyleAttributeTest * lsaTestPtr;
3100 for (lsaTestPtr = lsaTests; lsaTestPtr->locale != NULL; lsaTestPtr++) {
3101 UErrorCode status = U_ZERO_ERROR;
3102 UNumberFormat * unum = unum_open(lsaTestPtr->style, NULL, 0, lsaTestPtr->locale, NULL, &status);
3103 if ( U_FAILURE(status) ) {
3104 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr->style, lsaTestPtr->locale, u_errorName(status));
3105 } else {
3106 const ValueAndExpectedString * veItemPtr;
3107 if (lsaTestPtr->attribute >= 0) {
3108 unum_setAttribute(unum, (UNumberFormatAttribute)lsaTestPtr->attribute, lsaTestPtr->attrValue);
3109 }
3110 // ICU 62: should call minSignificantDigits in tandem with maxSignificantDigits.
3111 if (lsaTestPtr->attribute == UNUM_MIN_SIGNIFICANT_DIGITS) {
3112 unum_setAttribute(unum, UNUM_MAX_SIGNIFICANT_DIGITS, lsaTestPtr->attrValue);
3113 }
3114 for (veItemPtr = lsaTestPtr->veItems; veItemPtr->expected != NULL; veItemPtr++) {
3115 UChar uexp[kUBufSize];
3116 UChar uget[kUBufSize];
3117 int32_t uexplen, ugetlen;
3118
3119 status = U_ZERO_ERROR;
3120 uexplen = u_unescape(veItemPtr->expected, uexp, kUBufSize);
3121 ugetlen = unum_formatDouble(unum, veItemPtr->value, uget, kUBufSize, NULL, &status);
3122 if ( U_FAILURE(status) ) {
3123 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n",
3124 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, u_errorName(status));
3125 } else if (ugetlen != uexplen || u_strncmp(uget, uexp, uexplen) != 0) {
3126 char bexp[kBBufSize];
3127 char bget[kBBufSize];
3128 u_strToUTF8(bexp, kBBufSize, NULL, uexp, uexplen, &status);
3129 u_strToUTF8(bget, kBBufSize, NULL, uget, ugetlen, &status);
3130 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n",
3131 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, bexp, bget);
3132 }
3133 status = U_ZERO_ERROR;
3134 ugetlen = unum_formatDecimal(unum, veItemPtr->valueStr, -1, uget, kUBufSize, NULL, &status);
3135 if ( U_FAILURE(status) ) {
3136 log_err("FAIL: unum_formatDecimal style %d, locale %s, attr %d, valueStr %s: error %s\n",
3137 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->valueStr, u_errorName(status));
3138 } else if (ugetlen != uexplen || u_strncmp(uget, uexp, uexplen) != 0) {
3139 char bexp[kBBufSize];
3140 char bget[kBBufSize];
3141 u_strToUTF8(bexp, kBBufSize, NULL, uexp, uexplen, &status);
3142 u_strToUTF8(bget, kBBufSize, NULL, uget, ugetlen, &status);
3143 log_err("FAIL: unum_formatDecimal style %d, locale %s, attr %d, valueStr %s: expect \"%s\", get \"%s\"\n",
3144 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->valueStr, bexp, bget);
3145 }
3146 }
3147 unum_close(unum);
3148 }
3149 }
3150}
3151
3152static const UChar currpat[] = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; /* ¤#,##0.00 */
3153static const UChar parsetxt[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */
3154
3155static void TestParseCurrPatternWithDecStyle() {
3156 UErrorCode status = U_ZERO_ERROR;
3157 UNumberFormat *unumfmt = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
3158 if (U_FAILURE(status)) {
3159 log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status));
3160 } else {
3161 unum_applyPattern(unumfmt, FALSE, currpat, -1, NULL, &status);
3162 if (U_FAILURE(status)) {
3163 log_err_status(status, "unum_applyPattern failed: %s\n", u_errorName(status));
3164 } else {
3165 int32_t pos = 0;
3166 double value = unum_parseDouble(unumfmt, parsetxt, -1, &pos, &status);
3167 if (U_SUCCESS(status)) {
3168 log_err_status(status, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status), value);
3169 }
3170 }
3171 unum_close(unumfmt);
3172 }
3173}
3174
3175/*
3176 * Ticket #12684
3177 * Test unum_formatDoubleForFields (and UFieldPositionIterator)
3178 */
3179
3180typedef struct {
3181 int32_t field;
3182 int32_t beginPos;
3183 int32_t endPos;
3184} FieldsData;
3185
3186typedef struct {
3187 const char * locale;
3188 UNumberFormatStyle style;
3189 double value;
3190 const FieldsData * expectedFields;
3191} FormatForFieldsItem;
3192
3193static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */
3194
3195
3196/* "en_US", UNUM_CURRENCY, 123456.0 : "¤#,##0.00" => "$123,456.00" */
3197static const FieldsData fields_en_CURR[] = {
3198 { UNUM_CURRENCY_FIELD /*7*/, 0, 1 },
3199 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 4, 5 },
3200 { UNUM_INTEGER_FIELD /*0*/, 1, 8 },
3201 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 8, 9 },
3202 { UNUM_FRACTION_FIELD /*1*/, 9, 11 },
3203 { -1, -1, -1 },
3204};
3205/* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
3206static const FieldsData fields_en_PRCT[] = {
3207 { UNUM_SIGN_FIELD /*10*/, 0, 1 },
3208 { UNUM_INTEGER_FIELD /*0*/, 1, 3 },
3209 { UNUM_PERCENT_FIELD /*8*/, 3, 4 },
3210 { -1, -1, -1 },
3211};
3212/* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00 ¤" => "123,456.00 €" */
3213static const FieldsData fields_fr_CURR[] = {
3214 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 3, 4 },
3215 { UNUM_INTEGER_FIELD /*0*/, 0, 7 },
3216 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 7, 8 },
3217 { UNUM_FRACTION_FIELD /*1*/, 8, 10 },
3218 { UNUM_CURRENCY_FIELD /*7*/, 11, 12 },
3219 { -1, -1, -1 },
3220};
3221/* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */
3222static const FieldsData fields_en_PATN[] = {
3223 { UNUM_INTEGER_FIELD /*0*/, 1, 3 },
3224 { -1, -1, -1 },
3225};
3226
3227static const FormatForFieldsItem fffItems[] = {
3228 { "en_US", UNUM_CURRENCY_STANDARD, 123456.0, fields_en_CURR },
3229 { "en_US", UNUM_PERCENT, -0.34, fields_en_PRCT },
3230 { "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR },
3231 { "en_US", UNUM_PATTERN_DECIMAL, 12.0, fields_en_PATN },
3232 { NULL, (UNumberFormatStyle)0, 0, NULL },
3233};
3234
3235static void TestFormatForFields(void) {
3236 UErrorCode status = U_ZERO_ERROR;
3237 UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
3238 if ( U_FAILURE(status) ) {
3239 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
3240 } else {
3241 const FormatForFieldsItem * itemPtr;
3242 for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) {
3243 UNumberFormat* unum;
3244 status = U_ZERO_ERROR;
3245 unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)?
3246 unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status):
3247 unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
3248 if ( U_FAILURE(status) ) {
3249 log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3250 } else {
3251 UChar ubuf[kUBufSize];
3252 int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status);
3253 if ( U_FAILURE(status) ) {
3254 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3255 } else {
3256 const FieldsData * fptr;
3257 int32_t field, beginPos, endPos;
3258 for (fptr = itemPtr->expectedFields; TRUE; fptr++) {
3259 field = ufieldpositer_next(fpositer, &beginPos, &endPos);
3260 if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
3261 if (fptr->field >= 0) {
3262 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
3263 itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
3264 } else {
3265 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
3266 itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos);
3267 }
3268 break;
3269 }
3270 if (field < 0) {
3271 break;
3272 }
3273 }
3274 }
3275 unum_close(unum);
3276 }
3277 }
3278 ufieldpositer_close(fpositer);
3279 }
3280}
3281
3282static void Test12052_NullPointer() {
3283 UErrorCode status = U_ZERO_ERROR;
3284 static const UChar input[] = u"199a";
3285 UChar currency[200] = {0};
3286 UNumberFormat *theFormatter = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
3287 if (!assertSuccessCheck("unum_open() failed", &status, TRUE)) { return; }
3288 status = U_ZERO_ERROR;
3289 unum_setAttribute(theFormatter, UNUM_LENIENT_PARSE, 1);
3290 int32_t pos = 1;
3291 unum_parseDoubleCurrency(theFormatter, input, -1, &pos, currency, &status);
3292 assertEquals("should fail gracefully", "U_PARSE_ERROR", u_errorName(status));
3293 unum_close(theFormatter);
3294}
3295
3296typedef struct {
3297 const char* locale;
3298 const UChar* text; // text to parse
3299 UBool lenient; // leniency to use
3300 UBool intOnly; // whether to set PARSE_INT_ONLY
3301 UErrorCode intStatus; // expected status from parse
3302 int32_t intPos; // expected final pos from parse
3303 int32_t intValue; // expected value from parse
3304 UErrorCode doubStatus; // expected status from parseDouble
3305 int32_t doubPos; // expected final pos from parseDouble
3306 double doubValue; // expected value from parseDouble
3307 UErrorCode decStatus; // expected status from parseDecimal
3308 int32_t decPos; // expected final pos from parseDecimal
3309 const char* decString; // expected output string from parseDecimal
3310
3311} ParseCaseItem;
3312
3313static const ParseCaseItem parseCaseItems[] = {
3314 { "en", u"0,000", FALSE, FALSE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0, U_ZERO_ERROR, 5, "0" },
3315 { "en", u"0,000", TRUE, FALSE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0, U_ZERO_ERROR, 5, "0" },
3316 { "en", u",024", FALSE, FALSE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0, U_ZERO_ERROR, 4, "24" },
3317 { "en", u",024", TRUE, FALSE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0, U_ZERO_ERROR, 4, "24" },
3318 { "en", u"1000,000", FALSE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3319 { "en", u"1000,000", TRUE, FALSE, U_ZERO_ERROR, 8, 1000000, U_ZERO_ERROR, 8, 1000000.0, U_ZERO_ERROR, 8, "1000000" },
3320 { "en", u"", FALSE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3321 { "en", u"", TRUE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3322 { "en", u"9999990000503021", FALSE, FALSE, U_INVALID_FORMAT_ERROR, 16, 2147483647, U_ZERO_ERROR, 16, 9999990000503020.0, U_ZERO_ERROR, 16, "9999990000503021" },
3323 { "en", u"9999990000503021", FALSE, TRUE, U_INVALID_FORMAT_ERROR, 16, 2147483647, U_ZERO_ERROR, 16, 9999990000503020.0, U_ZERO_ERROR, 16, "9999990000503021" },
3324 { "en", u"1000000.5", FALSE, FALSE, U_ZERO_ERROR, 9, 1000000, U_ZERO_ERROR, 9, 1000000.5, U_ZERO_ERROR, 9, "1.0000005E+6" /* change from ICU-62nnn */},
3325 { "en", u"1000000.5", FALSE, TRUE, U_ZERO_ERROR, 7, 1000000, U_ZERO_ERROR, 7, 1000000.0, U_ZERO_ERROR, 7, "1000000" },
3326 { "en", u"123.5", FALSE, FALSE, U_ZERO_ERROR, 5, 123, U_ZERO_ERROR, 5, 123.5, U_ZERO_ERROR, 5, "123.5" },
3327 { "en", u"123.5", FALSE, TRUE, U_ZERO_ERROR, 3, 123, U_ZERO_ERROR, 3, 123.0, U_ZERO_ERROR, 3, "123" },
3328 { NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, NULL }
3329};
3330
3331static void TestParseCases(void) {
3332 const ParseCaseItem* itemPtr;
3333 for (itemPtr = parseCaseItems; itemPtr->locale != NULL; itemPtr++) {
3334 UErrorCode status = U_ZERO_ERROR;
3335 UNumberFormat* unumDec = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status);
3336 if (U_FAILURE(status)) {
3337 log_data_err("unum_open UNUM_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3338 continue;
3339 }
3340 int32_t intValue, parsePos, dclen;
3341 double doubValue;
3342 char decstr[32];
3343 unum_setAttribute(unumDec, UNUM_LENIENT_PARSE, itemPtr->lenient);
3344 unum_setAttribute(unumDec, UNUM_PARSE_INT_ONLY, itemPtr->intOnly);
3345
3346 parsePos = 0;
3347 status = U_ZERO_ERROR;
3348 intValue = unum_parse(unumDec, itemPtr->text, -1, &parsePos, &status);
3349 if (status != itemPtr->intStatus || parsePos != itemPtr->intPos || intValue != itemPtr->intValue) {
3350 char btext[32];
3351 u_austrcpy(btext, itemPtr->text);
3352 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parse expected status %s, pos %d, value %d;\n got %s, %d, %d\n",
3353 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3354 u_errorName(itemPtr->intStatus), itemPtr->intPos, itemPtr->intValue,
3355 u_errorName(status), parsePos, intValue);
3356 }
3357
3358 parsePos = 0;
3359 status = U_ZERO_ERROR;
3360 doubValue = unum_parseDouble(unumDec, itemPtr->text, -1, &parsePos, &status);
3361 if (status != itemPtr->doubStatus || parsePos != itemPtr->doubPos || doubValue != itemPtr->doubValue) {
3362 char btext[32];
3363 u_austrcpy(btext, itemPtr->text);
3364 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parseDouble expected status %s, pos %d, value %.1f;\n got %s, %d, %.1f\n",
3365 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3366 u_errorName(itemPtr->doubStatus), itemPtr->doubPos, itemPtr->doubValue,
3367 u_errorName(status), parsePos, doubValue);
3368 }
3369
3370 parsePos = 0;
3371 status = U_ZERO_ERROR;
3372 decstr[0] = 0;
3373 dclen = unum_parseDecimal(unumDec, itemPtr->text, -1, &parsePos, decstr, 32, &status);
3374 if (status != itemPtr->decStatus || parsePos != itemPtr->decPos || uprv_strcmp(decstr,itemPtr->decString) != 0) {
3375 char btext[32];
3376 u_austrcpy(btext, itemPtr->text);
3377 log_err("locale %s, text \"%s\", lenient %d, intOnly %d;\n parseDecimal expected status %s, pos %d, str \"%s\";\n got %s, %d, \"%s\"\n",
3378 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3379 u_errorName(itemPtr->decStatus), itemPtr->decPos, itemPtr->decString,
3380 u_errorName(status), parsePos, decstr);
3381 }
3382
3383 unum_close(unumDec);
3384 }
3385}
3386
3387typedef struct {
3388 const char* descrip;
3389 const char* locale;
3390 UNumberFormatStyle style;
3391 int32_t minInt;
3392 int32_t minFrac;
3393 int32_t maxFrac;
3394 double roundIncr;
3395 const UChar* expPattern;
3396 double valueToFmt;
3397 const UChar* expFormat;
3398} SetMaxFracAndRoundIncrItem;
3399
3400static const SetMaxFracAndRoundIncrItem maxFracAndRoundIncrItems[] = {
3401 // descrip locale style mnI mnF mxF rdInc expPat value expFmt
3402 { "01 en_US DEC 1/0/3/0.0", "en_US", UNUM_DECIMAL, 1, 0, 3, 0.0, u"#,##0.###", 0.128, u"0.128" },
3403 { "02 en_US DEC 1/0/1/0.0", "en_US", UNUM_DECIMAL, 1, 0, 1, 0.0, u"#,##0.#", 0.128, u"0.1" },
3404 { "03 en_US DEC 1/0/1/0.01", "en_US", UNUM_DECIMAL, 1, 0, 1, 0.01, u"#,##0.#", 0.128, u"0.1" },
3405 { "04 en_US DEC 1/1/1/0.01", "en_US", UNUM_DECIMAL, 1, 1, 1, 0.01, u"#,##0.0", 0.128, u"0.1" },
3406 { "05 en_US DEC 1/0/1/0.1", "en_US", UNUM_DECIMAL, 1, 0, 1, 0.1, u"#,##0.1", 0.128, u"0.1" }, // use incr
3407 { "06 en_US DEC 1/1/1/0.1", "en_US", UNUM_DECIMAL, 1, 1, 1, 0.1, u"#,##0.1", 0.128, u"0.1" }, // use incr
3408
3409 { "10 en_US DEC 1/0/1/0.02", "en_US", UNUM_DECIMAL, 1, 0, 1, 0.02, u"#,##0.#", 0.128, u"0.1" },
3410 { "11 en_US DEC 1/0/2/0.02", "en_US", UNUM_DECIMAL, 1, 0, 2, 0.02, u"#,##0.02", 0.128, u"0.12" }, // use incr
3411 { "12 en_US DEC 1/0/3/0.02", "en_US", UNUM_DECIMAL, 1, 0, 3, 0.02, u"#,##0.02#", 0.128, u"0.12" }, // use incr
3412 { "13 en_US DEC 1/1/1/0.02", "en_US", UNUM_DECIMAL, 1, 1, 1, 0.02, u"#,##0.0", 0.128, u"0.1" },
3413 { "14 en_US DEC 1/1/2/0.02", "en_US", UNUM_DECIMAL, 1, 1, 2, 0.02, u"#,##0.02", 0.128, u"0.12" }, // use incr
3414 { "15 en_US DEC 1/1/3/0.02", "en_US", UNUM_DECIMAL, 1, 1, 3, 0.02, u"#,##0.02#", 0.128, u"0.12" }, // use incr
3415 { "16 en_US DEC 1/2/2/0.02", "en_US", UNUM_DECIMAL, 1, 2, 2, 0.02, u"#,##0.02", 0.128, u"0.12" }, // use incr
3416 { "17 en_US DEC 1/2/3/0.02", "en_US", UNUM_DECIMAL, 1, 2, 3, 0.02, u"#,##0.02#", 0.128, u"0.12" }, // use incr
3417 { "18 en_US DEC 1/3/3/0.02", "en_US", UNUM_DECIMAL, 1, 3, 3, 0.02, u"#,##0.020", 0.128, u"0.120" }, // use incr
3418
3419 { "20 en_US DEC 1/1/1/0.0075", "en_US", UNUM_DECIMAL, 1, 1, 1, 0.0075, u"#,##0.0", 0.019, u"0.0" },
3420 { "21 en_US DEC 1/1/2/0.0075", "en_US", UNUM_DECIMAL, 1, 1, 2, 0.0075, u"#,##0.0075", 0.004, u"0.0075" }, // use incr
3421 { "22 en_US DEC 1/1/2/0.0075", "en_US", UNUM_DECIMAL, 1, 1, 2, 0.0075, u"#,##0.0075", 0.019, u"0.0225" }, // use incr
3422 { "23 en_US DEC 1/1/3/0.0075", "en_US", UNUM_DECIMAL, 1, 1, 3, 0.0075, u"#,##0.0075", 0.004, u"0.0075" }, // use incr
3423 { "24 en_US DEC 1/1/3/0.0075", "en_US", UNUM_DECIMAL, 1, 1, 3, 0.0075, u"#,##0.0075", 0.019, u"0.0225" }, // use incr
3424 { "25 en_US DEC 1/2/2/0.0075", "en_US", UNUM_DECIMAL, 1, 2, 2, 0.0075, u"#,##0.0075", 0.004, u"0.0075" }, // use incr
3425 { "26 en_US DEC 1/2/2/0.0075", "en_US", UNUM_DECIMAL, 1, 2, 2, 0.0075, u"#,##0.0075", 0.019, u"0.0225" }, // use incr
3426 { "27 en_US DEC 1/2/3/0.0075", "en_US", UNUM_DECIMAL, 1, 2, 3, 0.0075, u"#,##0.0075", 0.004, u"0.0075" }, // use incr
3427 { "28 en_US DEC 1/2/3/0.0075", "en_US", UNUM_DECIMAL, 1, 2, 3, 0.0075, u"#,##0.0075", 0.019, u"0.0225" }, // use incr
3428 { "29 en_US DEC 1/3/3/0.0075", "en_US", UNUM_DECIMAL, 1, 3, 3, 0.0075, u"#,##0.0075", 0.004, u"0.0075" }, // use incr
3429 { "2A en_US DEC 1/3/3/0.0075", "en_US", UNUM_DECIMAL, 1, 3, 3, 0.0075, u"#,##0.0075", 0.019, u"0.0225" }, // use incr
3430
3431 // Additions for rdar://51452216
3432 { "30 en_US DEC 1/0/1/0.01", "en_US", UNUM_DECIMAL, 1, 1, 3, 0.001, u"#,##0.001", 1.23456789, u"1.235" },
3433 { "31 en_US DEC 1/1/1/0.01", "en_US", UNUM_DECIMAL, 1, 1, 3, 0.001f, u"#,##0.001", 1.23456789, u"1.235" },
3434
3435 { NULL, NULL, UNUM_IGNORE, 0, 0, 0, 0.0, NULL, 0.0, NULL }
3436};
3437
3438// The following is copied from C++ number_patternstring.cpp for this C test.
3439//
3440// Determine whether a given roundingIncrement should be ignored for formatting
3441// based on the current maxFrac value (maximum fraction digits). For example a
3442// roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
3443// is 2 or more. Note that roundingIncrements are rounded in significance, so
3444// a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
3445// it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
3446// 0.005 is treated like 0.001 for significance). This is the reason for the
3447// initial doubling below.
3448// roundIncr must be non-zero
3449static UBool ignoreRoundingIncrement(double roundIncr, int32_t maxFrac) {
3450 if (maxFrac < 0) {
3451 return FALSE;
3452 }
3453 int32_t frac = 0;
3454 roundIncr *= 2.0;
3455 for (frac = 0; frac <= maxFrac && roundIncr <= 1.0; frac++, roundIncr *= 10.0);
3456 return (frac > maxFrac);
3457}
3458
3459static void TestSetMaxFracAndRoundIncr(void) {
3460 const SetMaxFracAndRoundIncrItem* itemPtr;
3461 for (itemPtr = maxFracAndRoundIncrItems; itemPtr->descrip != NULL; itemPtr++) {
3462 UChar ubuf[kUBufMax];
3463 char bbufe[kBBufMax];
3464 char bbufg[kBBufMax];
3465 int32_t ulen;
3466 UErrorCode status = U_ZERO_ERROR;
3467 UNumberFormat* unf = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
3468 if (U_FAILURE(status)) {
3469 log_data_err("locale %s: unum_open style %d fails with %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3470 continue;
3471 }
3472
3473 unum_setAttribute(unf, UNUM_MIN_INTEGER_DIGITS, itemPtr->minInt);
3474 unum_setAttribute(unf, UNUM_MIN_FRACTION_DIGITS, itemPtr->minFrac);
3475 unum_setAttribute(unf, UNUM_MAX_FRACTION_DIGITS, itemPtr->maxFrac);
3476 unum_setDoubleAttribute(unf, UNUM_ROUNDING_INCREMENT, itemPtr->roundIncr);
3477
3478 UBool roundIncrUsed = (itemPtr->roundIncr != 0.0 && !ignoreRoundingIncrement(itemPtr->roundIncr, itemPtr->maxFrac));
3479
3480 int32_t minInt = unum_getAttribute(unf, UNUM_MIN_INTEGER_DIGITS);
3481 if (minInt != itemPtr->minInt) {
3482 log_err("test %s: unum_getAttribute UNUM_MIN_INTEGER_DIGITS, expected %d, got %d\n",
3483 itemPtr->descrip, itemPtr->minInt, minInt);
3484 }
3485 int32_t minFrac = unum_getAttribute(unf, UNUM_MIN_FRACTION_DIGITS);
3486 if (minFrac != itemPtr->minFrac) {
3487 log_err("test %s: unum_getAttribute UNUM_MIN_FRACTION_DIGITS, expected %d, got %d\n",
3488 itemPtr->descrip, itemPtr->minFrac, minFrac);
3489 }
3490 // If incrementRounding is used, maxFrac is set equal to minFrac
3491 int32_t maxFrac = unum_getAttribute(unf, UNUM_MAX_FRACTION_DIGITS);
3492 // If incrementRounding is used, maxFrac is set equal to minFrac
3493 int32_t expMaxFrac = (roundIncrUsed)? itemPtr->minFrac: itemPtr->maxFrac;
3494 if (maxFrac != expMaxFrac) {
3495 log_err("test %s: unum_getAttribute UNUM_MAX_FRACTION_DIGITS, expected %d, got %d\n",
3496 itemPtr->descrip, expMaxFrac, maxFrac);
3497 }
3498 double roundIncr = unum_getDoubleAttribute(unf, UNUM_ROUNDING_INCREMENT);
3499 // If incrementRounding is not used, roundIncr is set to 0.0
3500 double expRoundIncr = (roundIncrUsed)? itemPtr->roundIncr: 0.0;
3501 if (roundIncr != expRoundIncr) {
3502 log_err("test %s: unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT, expected %f, got %f\n",
3503 itemPtr->descrip, expRoundIncr, roundIncr);
3504 }
3505
3506 status = U_ZERO_ERROR;
3507 ulen = unum_toPattern(unf, FALSE, ubuf, kUBufMax, &status);
3508 if ( U_FAILURE(status) ) {
3509 log_err("test %s: unum_toPattern fails with %s\n", itemPtr->descrip, u_errorName(status));
3510 } else if (u_strcmp(ubuf,itemPtr->expPattern)!=0) {
3511 u_austrcpy(bbufe, itemPtr->expPattern);
3512 u_austrcpy(bbufg, ubuf);
3513 log_err("test %s: unum_toPattern expect \"%s\", get \"%s\"\n", itemPtr->descrip, bbufe, bbufg);
3514 }
3515
3516 status = U_ZERO_ERROR;
3517 ulen = unum_formatDouble(unf, itemPtr->valueToFmt, ubuf, kUBufMax, NULL, &status);
3518 if ( U_FAILURE(status) ) {
3519 log_err("test %s: unum_formatDouble fails with %s\n", itemPtr->descrip, u_errorName(status));
3520 } else if (u_strcmp(ubuf,itemPtr->expFormat)!=0) {
3521 u_austrcpy(bbufe, itemPtr->expFormat);
3522 u_austrcpy(bbufg, ubuf);
3523 log_err("test %s: unum_formatDouble expect \"%s\", get \"%s\"\n", itemPtr->descrip, bbufe, bbufg);
3524 }
3525
3526 unum_close(unf);
3527 }
3528}
3529
3530static void TestIgnorePadding(void) {
3531 UErrorCode status = U_ZERO_ERROR;
3532 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
3533 if (U_FAILURE(status)) {
3534 log_data_err("unum_open UNUM_PATTERN_DECIMAL for en_US and NULL pattern fails:%s\n", u_errorName(status));
3535 } else {
3536 unum_setAttribute(unum, UNUM_GROUPING_USED, 0);
3537 unum_setAttribute(unum, UNUM_FORMAT_WIDTH, 0);
3538 unum_setTextAttribute(unum, UNUM_PADDING_CHARACTER, u"*", 1, &status);
3539 if (U_FAILURE(status)) {
3540 log_err("unum_setTextAttribute UNUM_PADDING_CHARACTER to '*' fails: %s\n", u_errorName(status));
3541 } else {
3542 unum_setAttribute(unum, UNUM_PADDING_POSITION, 0);
3543 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
3544 unum_setAttribute(unum, UNUM_MAX_INTEGER_DIGITS, 8);
3545 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
3546 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 0);
3547
3548 UChar ubuf[kUBufMax];
3549 int32_t ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
3550 if (U_FAILURE(status)) {
3551 log_err("unum_toPattern fails: %s\n", u_errorName(status));
3552 } else {
3553 char bbuf[kBBufMax];
3554 if (ulen > 0 && ubuf[0]==u'*') {
3555 ubuf[kUBufMax-1] = 0; // ensure zero termination
3556 u_austrncpy(bbuf, ubuf, kBBufMax);
3557 log_err("unum_toPattern result should ignore padding but get %s\n", bbuf);
3558 }
3559 unum_applyPattern(unum, FALSE, ubuf, ulen, NULL, &status);
3560 if (U_FAILURE(status)) {
3561 log_err("unum_applyPattern fails: %s\n", u_errorName(status));
3562 } else {
3563 ulen = unum_formatDecimal(unum, "24", -1, ubuf, kUBufMax, NULL, &status);
3564 if (U_FAILURE(status)) {
3565 log_err("unum_formatDecimal fails: %s\n", u_errorName(status));
3566 } else if (u_strcmp(ubuf, u"24") != 0) {
3567 ubuf[kUBufMax-1] = 0; // ensure zero termination
3568 u_austrncpy(bbuf, ubuf, kBBufMax);
3569 log_err("unum_formatDecimal result expect 24 but get %s\n", bbuf);
3570 }
3571 }
3572 }
3573 }
3574 unum_close(unum);
3575 }
3576}
3577
3578typedef struct {
3579 const char* locale;
3580 double value;
3581 const UChar* formatLimitPrecision;
3582 const UChar* formatFullPrecision;
3583} FormatPrecisionItem;
3584
3585static const FormatPrecisionItem formatPrecisionItems[] = {
3586 { "en_US", 0.33333333 - 0.00333333, u"0.33", u"0.32999999999999996" },
3587 { "en_US", 0.07 * 100.0, u"7", u"7.000000000000001" },
3588 { NULL, 0.0, NULL, NULL }
3589};
3590
3591static const UChar* patternTestPrecision = u"#0.################################################################################"; // 80 fraction places
3592
3593// Currently Apple only
3594static void TestFormatPrecision(void) {
3595 const FormatPrecisionItem* itemPtr;
3596 for (itemPtr = formatPrecisionItems; itemPtr->locale != NULL; itemPtr++) {
3597 UErrorCode status = U_ZERO_ERROR;
3598 UParseError perr;
3599 UNumberFormat *unum = unum_open(UNUM_PATTERN_DECIMAL, patternTestPrecision, -1, itemPtr->locale, &perr, &status);
3600 if (U_FAILURE(status)) {
3601 log_data_err("unum_open UNUM_PATTERN_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3602 continue;
3603 }
3604 UChar ubuf[kUBufSize];
3605 int32_t ulen;
3606 UFieldPosition fpos;
3607 UBool formatFullPrecision;
3608
3609 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3610 if (formatFullPrecision) {
3611 log_err("unum_getAttribute, default for UNUM_FORMAT_WITH_FULL_PRECISION is not FALSE\n");
3612 } else {
3613 fpos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
3614 fpos.beginIndex = 0;
3615 fpos.endIndex = 0;
3616 status = U_ZERO_ERROR;
3617 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3618 if (U_FAILURE(status)) {
3619 log_err("unum_formatDouble locale %s val %.20f limit precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3620 } else if (ulen != u_strlen(itemPtr->formatLimitPrecision) || u_strcmp(ubuf, itemPtr->formatLimitPrecision) != 0) {
3621 char bbufe[kBBufSize];
3622 char bbufg[kBBufSize];
3623 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatLimitPrecision, -1, &status);
3624 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3625 log_err("unum_formatDouble locale %s val %.20f limit precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3626 }
3627 }
3628
3629 unum_setAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION, TRUE);
3630 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3631 if (!formatFullPrecision) {
3632 log_err("unum_getAttribute, after set UNUM_FORMAT_WITH_FULL_PRECISION is not TRUE\n");
3633 } else {
3634 fpos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
3635 fpos.beginIndex = 0;
3636 fpos.endIndex = 0;
3637 status = U_ZERO_ERROR;
3638 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3639 if (U_FAILURE(status)) {
3640 log_err("unum_formatDouble locale %s val %.20f full precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3641 } else if (ulen != u_strlen(itemPtr->formatFullPrecision) || u_strcmp(ubuf, itemPtr->formatFullPrecision) != 0) {
3642 char bbufe[kBBufSize];
3643 char bbufg[kBBufSize];
3644 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatFullPrecision, -1, &status);
3645 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3646 log_err("unum_formatDouble locale %s val %.20f full precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3647 }
3648 }
3649
3650 unum_close(unum);
3651 }
3652}
3653
3654// Apple only for <rdar://problem/52538227>
3655static void TestSetSigDigAndRoundIncr(void) {
3656 UErrorCode status = U_ZERO_ERROR;
3657 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, u"#", 1, "en_US", NULL, &status);
3658 if ( U_FAILURE(status) ) {
3659 log_data_err("unum_open UNUM_PATTERN_DECIMAL # for \"en_US\" fails with %s\n", u_errorName(status));
3660 } else {
3661 static const double value = 1.034000;
3662 UChar ubuf[kUBufMax];
3663 char bbuf[kBBufMax];
3664 int32_t ulen;
3665
3666 unum_setAttribute(unum, UNUM_MAX_INTEGER_DIGITS, 42);
3667 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 0);
3668 unum_setAttribute(unum, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP); // =6
3669 unum_setDoubleAttribute(unum, UNUM_ROUNDING_INCREMENT, 0.01);
3670 unum_setAttribute(unum, UNUM_SIGNIFICANT_DIGITS_USED, 1);
3671 unum_setAttribute(unum, UNUM_MAX_SIGNIFICANT_DIGITS, 5);
3672 unum_setAttribute(unum, UNUM_MIN_SIGNIFICANT_DIGITS, 1);
3673
3674 log_info("unum_getAttribute minSig %d maxSig %d sigUsed %d\n",
3675 unum_getAttribute(unum,UNUM_MIN_SIGNIFICANT_DIGITS), unum_getAttribute(unum,UNUM_MAX_SIGNIFICANT_DIGITS),
3676 unum_getAttribute(unum,UNUM_SIGNIFICANT_DIGITS_USED));
3677 log_info("unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT %f\n", unum_getDoubleAttribute(unum,UNUM_SIGNIFICANT_DIGITS_USED));
3678 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
3679 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
3680 if ( U_SUCCESS(status) ) {
3681 log_info("unum_toPattern (%d): %s\n", ulen, bbuf);
3682 }
3683
3684 status = U_ZERO_ERROR;
3685 ulen = unum_formatDouble(unum, value, ubuf, kUBufMax, NULL, &status);
3686 if ( U_FAILURE(status) ) {
3687 log_err("unum_formatDouble value %.1f status %s\n", value, u_errorName(status));
3688 } else if (u_strcmp(ubuf,u"1.03") != 0) {
3689 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
3690 log_err("unum_formatDouble value %.1f expected 1.03, got %s\n", value, bbuf);
3691 }
3692 unum_close(unum);
3693 }
3694}
3695
3696// Apple for <rdar://problem/46755430>
3697typedef struct {
3698 const char* descrip;
3699 const char* locale;
3700 const UChar* setPosPrefix;
3701 const UChar* setPosSuffix;
3702 const UChar* setNegPrefix;
3703 const UChar* setNegSuffix;
3704 const UChar* expPosPrefix;
3705 const UChar* expPosSuffix;
3706 const UChar* expNegPrefix;
3707 const UChar* expNegSuffix;
3708 const UChar* expPattern;
3709 double value;
3710 const UChar* expPosFormat;
3711 const UChar* expNegFormat;
3712} SetAffixOnCurrFmtItem;
3713
3714static const SetAffixOnCurrFmtItem affixOnCurrFmtItems[] = {
3715 // descrip loc sPP sPS sNP sNS ePP ePS eNP eNS ePattern value ePosFmt eNegFmt
3716 { "01 en set no affix ", "en", NULL, NULL, NULL, NULL, u"¤", u"", u"-¤", u"", u"¤#,##0.00", 123.4, u"¤123.40", u"-¤123.40" },
3717 { "02 en set + prefix", "en", u"$", NULL, NULL, NULL, u"$", u"", u"-¤", u"", u"$#,##0.00;-¤#,##0.00", 123.4, u"$123.40", u"-¤123.40" },
3718 { "03 en set +- prefix", "en", u"$", NULL, u"-$", NULL, u"$", u"", u"-$", u"", u"$#,##0.00;'-'$#,##0.00", 123.4, u"$123.40", u"-$123.40" },
3719 { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.0,NULL,NULL }
3720};
3721
3722// Apple only for <rdar://problem/46755430>
3723static void TestSetAffixOnCurrFmt(void) {
3724 const SetAffixOnCurrFmtItem* itemPtr;
3725 for (itemPtr = affixOnCurrFmtItems; itemPtr->descrip != NULL; itemPtr++) {
3726 UChar ubuf[kUBufMax];
3727 char bbufe[kBBufMax];
3728 char bbufg[kBBufMax];
3729 int32_t ulen;
3730 UErrorCode status = U_ZERO_ERROR;
3731 UNumberFormat* unf = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
3732 if (U_FAILURE(status)) {
3733 log_data_err("locale %s: unum_open UNUM_CURRENCY fails with %s\n", itemPtr->locale, u_errorName(status));
3734 continue;
3735 }
3736
3737 if (itemPtr->setPosPrefix) {
3738 status = U_ZERO_ERROR;
3739 unum_setTextAttribute(unf, UNUM_POSITIVE_PREFIX, itemPtr->setPosPrefix, -1, &status);
3740 if (U_FAILURE(status)) {
3741 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3742 }
3743 }
3744 if (itemPtr->setPosSuffix) {
3745 status = U_ZERO_ERROR;
3746 unum_setTextAttribute(unf, UNUM_POSITIVE_SUFFIX, itemPtr->setPosSuffix, -1, &status);
3747 if (U_FAILURE(status)) {
3748 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3749 }
3750 }
3751 if (itemPtr->setNegPrefix) {
3752 status = U_ZERO_ERROR;
3753 unum_setTextAttribute(unf, UNUM_NEGATIVE_PREFIX, itemPtr->setNegPrefix, -1, &status);
3754 if (U_FAILURE(status)) {
3755 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3756 }
3757 }
3758 if (itemPtr->setNegSuffix) {
3759 status = U_ZERO_ERROR;
3760 unum_setTextAttribute(unf, UNUM_NEGATIVE_SUFFIX, itemPtr->setNegSuffix, -1, &status);
3761 if (U_FAILURE(status)) {
3762 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3763 }
3764 }
3765
3766 status = U_ZERO_ERROR;
3767 ulen = unum_getTextAttribute(unf, UNUM_POSITIVE_PREFIX, ubuf, kUBufMax, &status);
3768 if (U_FAILURE(status)) {
3769 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3770 } else if (u_strcmp(ubuf,itemPtr->expPosPrefix)!=0) {
3771 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosPrefix, -1, &status);
3772 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3773 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3774 }
3775 status = U_ZERO_ERROR;
3776 ulen = unum_getTextAttribute(unf, UNUM_POSITIVE_SUFFIX, ubuf, kUBufMax, &status);
3777 if (U_FAILURE(status)) {
3778 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3779 } else if (u_strcmp(ubuf,itemPtr->expPosSuffix)!=0) {
3780 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosSuffix, -1, &status);
3781 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3782 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3783 }
3784 status = U_ZERO_ERROR;
3785 ulen = unum_getTextAttribute(unf, UNUM_NEGATIVE_PREFIX, ubuf, kUBufMax, &status);
3786 if (U_FAILURE(status)) {
3787 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3788 } else if (u_strcmp(ubuf,itemPtr->expNegPrefix)!=0) {
3789 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegPrefix, -1, &status);
3790 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3791 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3792 }
3793 status = U_ZERO_ERROR;
3794 ulen = unum_getTextAttribute(unf, UNUM_NEGATIVE_SUFFIX, ubuf, kUBufMax, &status);
3795 if (U_FAILURE(status)) {
3796 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3797 } else if (u_strcmp(ubuf,itemPtr->expNegSuffix)!=0) {
3798 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegSuffix, -1, &status);
3799 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3800 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3801 }
3802 status = U_ZERO_ERROR;
3803 ulen = unum_toPattern(unf, FALSE, ubuf, kUBufMax, &status);
3804 if (U_FAILURE(status)) {
3805 log_err("test %s: unum_toPattern fails with %s\n", itemPtr->descrip, u_errorName(status));
3806 } else if (u_strcmp(ubuf,itemPtr->expPattern)!=0) {
3807 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPattern, -1, &status);
3808 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3809 log_err("test %s: unum_toPattern expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3810 }
3811
3812 status = U_ZERO_ERROR;
3813 ulen = unum_formatDouble(unf, itemPtr->value, ubuf, kUBufMax, NULL, &status);
3814 if (U_FAILURE(status)) {
3815 log_err("test %s: unum_formatDouble positive fails with %s\n", itemPtr->descrip, u_errorName(status));
3816 } else if (u_strcmp(ubuf,itemPtr->expPosFormat)!=0) {
3817 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosFormat, -1, &status);
3818 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3819 log_err("test %s: unum_formatDouble positive expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3820 }
3821 status = U_ZERO_ERROR;
3822 ulen = unum_formatDouble(unf, -1.0*itemPtr->value, ubuf, kUBufMax, NULL, &status);
3823 if (U_FAILURE(status)) {
3824 log_err("test %s: unum_formatDouble negative fails with %s\n", itemPtr->descrip, u_errorName(status));
3825 } else if (u_strcmp(ubuf,itemPtr->expNegFormat)!=0) {
3826 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegFormat, -1, &status);
3827 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3828 log_err("test %s: unum_formatDouble negative expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3829 }
3830
3831 unum_close(unf);
3832 }
3833}
3834
3835// Apple only for <rdar://problem/46915356>
3836static void TestParseWithEmptyCurr(void) {
3837 UErrorCode status = U_ZERO_ERROR;
3838 UNumberFormat* unum = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
3839 if (U_FAILURE(status)) {
3840 log_data_err("unum_open UNUM_CURRENCY for \"en_US\" fails with %s\n", u_errorName(status));
3841 } else {
3842 unum_setSymbol(unum, UNUM_CURRENCY_SYMBOL, u"", 0, &status);
3843 if (U_FAILURE(status)) {
3844 log_err("unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s\n", u_errorName(status));
3845 } else {
3846 char bbuf[kBBufMax] = { 0 };
3847 UChar curr[4] = { 0 };
3848 int32_t ppos, blen;
3849 double val;
3850 const UChar* text = u"3";
3851
3852 status = U_ZERO_ERROR;
3853 ppos = 0;
3854 blen = unum_parseDecimal(unum, text, -1, &ppos, bbuf, kBBufMax, &status);
3855 if (U_FAILURE(status)) {
3856 log_err("unum_parseDecimal u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status), ppos);
3857 } else if (ppos != 1 || blen != 1 || bbuf[0] != '3') {
3858 log_err("unum_parseDecimal expect ppos 1, blen 1, str 3; get %d, %d, %s\n", ppos, blen, bbuf);
3859 }
3860
3861 status = U_ZERO_ERROR;
3862 ppos = 0;
3863 val = unum_parseDouble(unum, text, -1, &ppos, &status);
3864 if (U_FAILURE(status)) {
3865 log_err("unum_parseDouble u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status), ppos);
3866 } else if (ppos != 1 || val != 3.0) {
3867 log_err("unum_parseDouble expect ppos 1, val 3.0; get %d, %.2f\n", ppos, val);
3868 }
3869
3870 status = U_ZERO_ERROR;
3871 ppos = 0;
3872 val = unum_parseDoubleCurrency(unum, text, -1, &ppos, curr, &status);
3873 if (U_SUCCESS(status)) {
3874 log_err("unum_parseDoubleCurrency u\"3\" with empty curr symbol succeeds, get ppos %d, val %.2f\n", ppos, val);
3875 }
3876 }
3877 unum_close(unum);
3878 }
3879
3880 // Additions for <rdar://problem/51938595>
3881 // "¤#,##0.00" "¤ #,##0.00" "#,##0.00 ¤" "#,##,##0.00¤"
3882 static const char* locales[] = {"en_US", "en_NO", "en_CZ", "en_BD", NULL };
3883 const char ** localesPtr = locales;
3884 const char* locale;
3885 while ((locale = *localesPtr++) != NULL) {
3886 status = U_ZERO_ERROR;
3887 unum = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status);
3888 if (U_FAILURE(status)) {
3889 log_data_err("locale %s unum_open UNUM_CURRENCY fails with %s\n", locale, u_errorName(status));
3890 } else {
3891 char bbuf[kBBufMax] = { 0 };
3892 UChar curr[4] = { 0 };
3893 UChar ubuf[kUBufMax];
3894 int32_t ppos, blen, ulen;
3895 const double posValToUse = 37.0;
3896 const double negValToUse = -3.0;
3897 double val;
3898
3899 status = U_ZERO_ERROR;
3900 unum_setSymbol(unum, UNUM_CURRENCY_SYMBOL, u"", 0, &status);
3901 if (U_FAILURE(status)) {
3902 log_err("locale %s unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s, skipping\n", locale, u_errorName(status));
3903 continue;
3904 }
3905
3906 status = U_ZERO_ERROR;
3907 ulen = unum_formatDouble(unum, posValToUse, ubuf, kUBufMax, NULL, &status);
3908 if (U_FAILURE(status)) {
3909 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale, posValToUse, u_errorName(status));
3910 continue;
3911 }
3912
3913 status = U_ZERO_ERROR;
3914 ppos = 0;
3915 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3916 if (U_FAILURE(status)) {
3917 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, posValToUse);
3918 } else if (ppos != ulen || val != posValToUse) {
3919 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, posValToUse, ppos, val);
3920 }
3921
3922 status = U_ZERO_ERROR;
3923 ulen = unum_formatDouble(unum, negValToUse, ubuf, kUBufMax, NULL, &status);
3924 if (U_FAILURE(status)) {
3925 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale, negValToUse, u_errorName(status));
3926 continue;
3927 }
3928
3929 status = U_ZERO_ERROR;
3930 ppos = 0;
3931 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3932 if (U_FAILURE(status)) {
3933 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, negValToUse);
3934 } else if (ppos != ulen || val != negValToUse) {
3935 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, negValToUse, ppos, val);
3936 }
3937
3938 status = U_ZERO_ERROR;
3939 unum_applyPattern(unum, FALSE, u"#,##0.00¤", -1, NULL, &status);
3940 if (U_FAILURE(status)) {
3941 log_err("locale %s unum_applyPattern \"#,##0.00¤\" fails with %s, skipping\n", locale, u_errorName(status));
3942 continue;
3943 }
3944
3945 status = U_ZERO_ERROR;
3946 ulen = unum_formatDouble(unum, posValToUse, ubuf, kUBufMax, NULL, &status);
3947 if (U_FAILURE(status)) {
3948 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale, posValToUse, u_errorName(status));
3949 continue;
3950 }
3951
3952 status = U_ZERO_ERROR;
3953 ppos = 0;
3954 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3955 if (U_FAILURE(status)) {
3956 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, posValToUse);
3957 } else if (ppos != ulen || val != posValToUse) {
3958 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, posValToUse, ppos, val);
3959 }
3960
3961 status = U_ZERO_ERROR;
3962 ulen = unum_formatDouble(unum, negValToUse, ubuf, kUBufMax, NULL, &status);
3963 if (U_FAILURE(status)) {
3964 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale, negValToUse, u_errorName(status));
3965 continue;
3966 }
3967
3968 status = U_ZERO_ERROR;
3969 ppos = 0;
3970 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3971 if (U_FAILURE(status)) {
3972 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, negValToUse);
3973 } else if (ppos != ulen || val != negValToUse) {
3974 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, negValToUse, ppos, val);
3975 }
3976
3977 unum_close(unum);
3978 }
3979 }
3980}
3981
3982// Apple only for <rdar://problem/50113359>
3983static const UChar* pat1 = u"#.##E+00;-#.##E+00";
3984static void TestSciNotationNumbers(void) {
3985 UErrorCode status = U_ZERO_ERROR;
3986 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
3987 if ( U_FAILURE(status) ) {
3988 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status));
3989 } else {
3990 unum_applyPattern(unum, FALSE, pat1, u_strlen(pat1), NULL, &status);
3991 if ( U_FAILURE(status) ) {
3992 log_err("unum_applyPattern fails with %s\n", u_errorName(status));
3993 } else {
3994 double value;
3995 UChar ubuf[kUBufMax];
3996 char bbuf[kBBufMax];
3997 int32_t ulen;
3998
3999 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
4000 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 2147483647);
4001 log_info("unum_getAttribute minInt %d maxInt %d minFrac %d maxFrac %d\n",
4002 unum_getAttribute(unum,UNUM_MIN_INTEGER_DIGITS), unum_getAttribute(unum,UNUM_MAX_INTEGER_DIGITS),
4003 unum_getAttribute(unum,UNUM_MIN_FRACTION_DIGITS), unum_getAttribute(unum,UNUM_MAX_FRACTION_DIGITS));
4004 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
4005 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4006 if ( U_SUCCESS(status) ) {
4007 log_info("unum_toPattern (%d): %s\n", ulen, bbuf);
4008 }
4009
4010 for (value = 10.0; value < 1000000000.0; value *= 10.0) {
4011 status = U_ZERO_ERROR;
4012 ulen = unum_formatDouble(unum, value, ubuf, kUBufMax, NULL, &status);
4013 if ( U_FAILURE(status) ) {
4014 log_err("unum_formatDouble value %.1f status %s\n", value, u_errorName(status));
4015 } else if (u_strncmp(ubuf,u"1E+0",4) != 0) {
4016 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4017 log_err("unum_formatDouble value %.1f expected result to begin with 1E+0, got %s\n", value, bbuf);
4018 }
4019 }
4020 }
4021 unum_close(unum);
4022 }
4023}
4024
4025// Apple only for <rdar://problem/51601250>
4026static const UChar* patFmt3Exp = u"0.000E+00";
4027static void TestSciNotationPrecision(void) {
4028 UErrorCode status = U_ZERO_ERROR;
4029 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
4030 if ( U_FAILURE(status) ) {
4031 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status));
4032 } else {
4033 unum_applyPattern(unum, FALSE, pat1, u_strlen(pat1), NULL, &status);
4034 if ( U_FAILURE(status) ) {
4035 log_err("unum_applyPattern fails with %s\n", u_errorName(status));
4036 } else {
4037 double value;
4038 UChar ubuf[kUBufMax];
4039 char bexp[kBBufMax];
4040 char bget[kBBufMax];
4041 int32_t ulen;
4042
4043 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 3);
4044 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 3);
4045 unum_setAttribute(unum, UNUM_GROUPING_USED, 0);
4046
4047 status = U_ZERO_ERROR;
4048 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
4049 if ( U_FAILURE(status) ) {
4050 log_err("unum_toPattern fails with %s\n", u_errorName(status));
4051 } else if (u_strcmp(ubuf,patFmt3Exp) != 0) {
4052 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4053 log_info("unum_toPattern, get \"%s\"\n", bget);
4054 }
4055
4056 status = U_ZERO_ERROR;
4057 ulen = unum_formatDouble(unum, 0.0, ubuf, ulen, NULL, &status);
4058 if ( U_FAILURE(status) ) {
4059 log_err("unum_formatDouble fails with %s\n", u_errorName(status));
4060 } else if (u_strcmp(ubuf,patFmt3Exp) != 0) {
4061 u_strToUTF8(bexp, kBBufMax, NULL, patFmt3Exp, -1, &status);
4062 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4063 log_err("unum_formatDouble error, expect \"%s\", get \"%s\"\n", bexp, bget);
4064 }
4065 }
4066 unum_close(unum);
4067 }
4068}
4069
4070// Apple only for <rdar://problem/49808819>
4071static const char* minGroupLocale = "pt_PT"; // has minimumGroupingDigits{"2"}
4072typedef struct {
4073 double value;
4074 const char* string;
4075 const UChar* expectDecimal;
4076 const UChar* expectCurrency;
4077} TestMinGroupItem;
4078static const TestMinGroupItem minGroupItems[] = {
4079 { 123.0, "123.0", u"123,00", u"123,00 €" },
4080 { 1234.0, "1234.0", u"1234,00", u"1234,00 €" },
4081 { 12345.0, "12345.0", u"12 345,00", u"12 345,00 €" },
4082 { 123456.0, "123456.0", u"123 456,00", u"123 456,00 €" },
4083 { 1234567.0, "1234567.0", u"1 234 567,00", u"1 234 567,00 €" },
4084 { 12345678.0, "12345678.0", u"12 345 678,00", u"12 345 678,00 €" },
4085 { 0.0, NULL, NULL, NULL } // terminator
4086};
4087static void TestMinimumGrouping(void) {
4088 UErrorCode status = U_ZERO_ERROR;
4089 UNumberFormat* unumd = unum_open(UNUM_DECIMAL, NULL, 0, minGroupLocale, NULL, &status);
4090 UNumberFormat* unumc = unum_open(UNUM_CURRENCY, NULL, 0, minGroupLocale, NULL, &status);
4091 if ( U_FAILURE(status) ) {
4092 log_data_err("unum_open UNUM_PATTERN_DECIMAL/CURRENCY for %s fails with %s\n", minGroupLocale, u_errorName(status));
4093 } else {
4094 const TestMinGroupItem* itemPtr;
4095 unum_setAttribute(unumd, UNUM_MIN_FRACTION_DIGITS, 2);
4096 for (itemPtr = minGroupItems; itemPtr->value != 0.0; itemPtr++) {
4097 UChar ubuf[kUBufMax];
4098 char bbufe[kBBufMax];
4099 char bbufg[kBBufMax];
4100 int32_t ulen;
4101
4102 status = U_ZERO_ERROR;
4103 ulen = unum_formatDecimal(unumd, itemPtr->string, -1, ubuf, kUBufMax, NULL, &status);
4104 if ( U_FAILURE(status) ) {
4105 log_err("unum_formatDecimal DEC for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4106 } else if (u_strcmp(ubuf, itemPtr->expectDecimal) != 0) {
4107 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectDecimal, -1, &status);
4108 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4109 log_err("unum_formatDecimal DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4110 minGroupLocale, itemPtr->value, bbufe, bbufg);
4111 }
4112
4113 status = U_ZERO_ERROR;
4114 ulen = unum_formatDouble(unumd, itemPtr->value, ubuf, kUBufMax, NULL, &status);
4115 if ( U_FAILURE(status) ) {
4116 log_err("unum_formatDouble DEC for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4117 } else if (u_strcmp(ubuf, itemPtr->expectDecimal) != 0) {
4118 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectDecimal, -1, &status);
4119 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4120 log_err("unum_formatDouble DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4121 minGroupLocale, itemPtr->value, bbufe, bbufg);
4122 }
4123
4124 status = U_ZERO_ERROR;
4125 ulen = unum_formatDouble(unumc, itemPtr->value, ubuf, kUBufMax, NULL, &status);
4126 if ( U_FAILURE(status) ) {
4127 log_err("unum_formatDouble CUR for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4128 } else if (u_strcmp(ubuf, itemPtr->expectCurrency) != 0) {
4129 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectCurrency, -1, &status);
4130 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4131 log_err("unum_formatDouble CUR for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4132 minGroupLocale, itemPtr->value, bbufe, bbufg);
4133 }
4134 }
4135 unum_close(unumc);
4136 unum_close(unumd);
4137 }
4138}
4139
4140// Apple only for <rdar://problem/49120648>
4141static const char* const numSysLocales[] = {
4142 "en_US", "en_US@numbers=arab", "en_US@numbers=roman", "en_US@numbers=grek", "en_US@numbers=hebr",
4143 "zh@numbers=hanidec", "zh_Hant@numbers=traditional", "en@numbers=finance", NULL
4144};
4145static void TestNumberSystemsMultiplier(void) {
4146 const char* const* localesPtr = numSysLocales;
4147 const char* locale;
4148 while ((locale = *localesPtr++) != NULL) {
4149 UErrorCode status = U_ZERO_ERROR;
4150 UNumberFormat *unum = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status);
4151 if ( U_FAILURE(status) ) {
4152 log_data_err("unum_open UNUM_DECIMAL for %s fails with %s\n", locale, u_errorName(status));
4153 } else {
4154 int32_t multiplier = unum_getAttribute(unum, UNUM_MULTIPLIER);
4155 log_info("for locale %s with UNUM_DECIMAL, UNUM_MULTIPLIER is %d\n", locale, multiplier);
4156 unum_close(unum);
4157 }
4158 }
4159}
4160
4161// Apple only for <rdar://problem/39156484>
4162typedef struct {
4163 const char* locale;
4164 const UChar* stringToParse;
4165 double expectValue;
4166 int32_t expectPos;
4167} ParseScientificItem;
4168static const ParseScientificItem parseSciItems[] = {
4169 { "en_US", u"4E\u200E+05", 400000.0, 6 },
4170 { "en_US", u"4E+05", 400000.0, 5 },
4171 { "en_US", u"4E\u200E-02", 0.04, 6 },
4172 { "en_US", u"4E-02", 0.04, 5 },
4173 { "he_IL", u"4E\u200E+05", 400000.0, 6 },
4174 { "he_IL", u"4E+05", 400000.0, 5 },
4175 { "he_IL", u"4E\u200E-02", 0.04, 6 },
4176 { "he_IL", u"4E-02", 0.04, 5 },
4177 { "en@numbers=arabext", u"\u06F4\u00D7\u06F1\u06F0^\u200E+\u200E\u06F0\u06F5", 400000.0, 10 },
4178 { "en@numbers=arabext", u"\u06F4\u00D7\u06F1\u06F0^+\u06F0\u06F5", 400000.0, 8 },
4179 { NULL,NULL, 0.0, 0 } // terminator
4180};
4181static void TestParseScientific(void) {
4182 const ParseScientificItem* itemPtr;
4183 for (itemPtr = parseSciItems; itemPtr->locale != NULL; itemPtr++) {
4184 UErrorCode status = U_ZERO_ERROR;
4185 UNumberFormat *unum = unum_open(UNUM_SCIENTIFIC, NULL, 0, itemPtr->locale, NULL, &status);
4186 if ( U_FAILURE(status) ) {
4187 log_data_err("unum_open UNUM_SCIENTIFIC for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4188 } else {
4189 int32_t parsePos = 0;
4190 double result = unum_parseDouble(unum, itemPtr->stringToParse, -1, &parsePos, &status);
4191 if ( U_FAILURE(status) ) {
4192 log_err("unum_parseDouble for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4193 } else if (result != itemPtr->expectValue || parsePos != itemPtr->expectPos) {
4194 log_err("unum_parseDouble for %s, expected result %.1f pos %d, got %.1f %d\n",
4195 itemPtr->locale, itemPtr->expectValue, itemPtr->expectPos, result, parsePos);
4196 }
4197 unum_close(unum);
4198 }
4199 }
4200}
4201
4202// Apple only for <rdar://problem/51985640>
4203typedef struct {
4204 const char* locale;
4205 const UChar* expCurrCode;
4206} LocaleCurrCodeItem;
4207static const LocaleCurrCodeItem currCodeItems[] = {
4208 { "en", u"" }, // curr ICU has "XXX"
4209 { "en@currency=EUR", u"EUR" },
4210 { "en_US", u"USD" },
4211 { "en_ZZ", u"XAG" },
4212 { "_US", u"USD" },
4213 { "_ZZ", u"XAG" },
4214 { "us", u"" }, // curr ICU has "XXX"
4215 { "", u"" }, // curr ICU has "XXX"
4216 { NULL, NULL }
4217};
4218static void TestCurrForUnkRegion(void) {
4219 const LocaleCurrCodeItem* itemPtr;
4220 for (itemPtr = currCodeItems; itemPtr->locale != NULL; itemPtr++) {
4221 UErrorCode status = U_ZERO_ERROR;
4222 UNumberFormat* unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
4223 if ( U_FAILURE(status) ) {
4224 log_data_err("unum_open UNUM_CURRENCY for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4225 } else {
4226 UChar ubuf[kUBufMax];
4227 int32_t ulen = unum_getTextAttribute(unum, UNUM_CURRENCY_CODE, ubuf, kUBufMax, &status);
4228 if ( U_FAILURE(status) ) {
4229 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4230 } else if (u_strcmp(ubuf,itemPtr->expCurrCode)!=0) {
4231 char bexp[kBBufMax];
4232 char bget[kBBufMax];
4233 u_strToUTF8(bexp, kBBufMax, NULL, itemPtr->expCurrCode, -1, &status);
4234 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4235 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect \"%s\" but get \"%s\"\n", itemPtr->locale, bexp, bget);
4236 }
4237 status = U_ZERO_ERROR;
4238 unum_setTextAttribute(unum, UNUM_CURRENCY_CODE, u"XXX", 3, &status);
4239 if ( U_FAILURE(status) ) {
4240 log_err("unum_setTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4241 } else {
4242 ulen = unum_getTextAttribute(unum, UNUM_CURRENCY_CODE, ubuf, kUBufMax, &status);
4243 if ( U_FAILURE(status) ) {
4244 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE XXX for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4245 } else if (u_strcmp(ubuf,u"XXX")!=0) {
4246 char bget[kBBufMax];
4247 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4248 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect XXX but get \"%s\"\n", itemPtr->locale, bget);
4249 }
4250 }
4251 unum_close(unum);
4252 }
4253 }
4254}
4255
4256static void TestMinIntMinFracZero(void) {
4257 UErrorCode status = U_ZERO_ERROR;
4258 UNumberFormat* unum = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
4259 if ( U_FAILURE(status) ) {
4260 log_data_err("unum_open UNUM_DECIMAL for en_US fails with %s\n", u_errorName(status));
4261 } else {
4262 UChar ubuf[kUBufMax];
4263 char bbuf[kBBufMax];
4264 int minInt, minFrac, ulen;
4265
4266 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
4267 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
4268 minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
4269 minFrac = unum_getAttribute(unum, UNUM_MIN_FRACTION_DIGITS);
4270 if (minInt != 0 || minFrac != 0) {
4271 log_err("after setting minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt, minFrac);
4272 }
4273 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
4274 if ( U_SUCCESS(status) ) {
4275 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4276 log_info("after setting minInt=minFrac=0, pattern (%d): %s\n", ulen, bbuf);
4277 }
4278
4279 status = U_ZERO_ERROR;
4280 ulen = unum_formatDouble(unum, 10.0, ubuf, kUBufMax, NULL, &status);
4281 if ( U_FAILURE(status) ) {
4282 log_err("unum_formatDouble 10.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4283 } else if (u_strcmp(ubuf, u"10") != 0) {
4284 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4285 log_err("unum_formatDouble 10.0 expected \"10\", got \"%s\"\n", bbuf);
4286 }
4287
4288 status = U_ZERO_ERROR;
4289 ulen = unum_formatDouble(unum, 0.9, ubuf, kUBufMax, NULL, &status);
4290 if ( U_FAILURE(status) ) {
4291 log_err("unum_formatDouble 0.9 ulen %d fails with %s\n", ulen, u_errorName(status));
4292 } else if (u_strcmp(ubuf, u".9") != 0) {
4293 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4294 log_err("unum_formatDouble 0.9 expected \".9\", got \"%s\"\n", bbuf);
4295 }
4296
4297 status = U_ZERO_ERROR;
4298 ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
4299 if ( U_FAILURE(status) ) {
4300 log_err("unum_formatDouble 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4301 } else if (u_strcmp(ubuf, u"0") != 0) {
4302 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4303 log_err("unum_formatDouble 0.0 expected \"0\", got \"%s\"\n", bbuf);
4304 }
4305
4306 unum_close(unum);
4307 }
4308}
4309
4310#if APPLE_ADDITIONS
4311#include <stdio.h>
4312#if U_PLATFORM_IS_DARWIN_BASED
4313#include <unistd.h>
4314#include <mach/mach_time.h>
4315#define GET_START() mach_absolute_time()
4316#define GET_DURATION(start, info) ((mach_absolute_time() - start) * info.numer)/info.denom
4317#elif !U_PLATFORM_HAS_WIN32_API
4318#include <unistd.h>
4319#include "putilimp.h"
4320#define GET_START() (uint64_t)uprv_getUTCtime()
4321#define GET_DURATION(start, info) ((uint64_t)uprv_getUTCtime() - start)
4322#else
4323#include "putilimp.h"
4324#define GET_START() (unsigned long long)uprv_getUTCtime()
4325#define GET_DURATION(start, info) ((unsigned long long)uprv_getUTCtime() - start)
4326#endif
4327
4328// Apple only for <rdar://problem/51672521>
4329
4330static void TestFormatDecPerf(void) {
4331 static const char* locales[] =
4332 { "en_US", "ar_EG", "ar_EG@numbers=latn", "zh_CN@numbers=traditional", NULL };
4333 static const UNumberFormatStyle styles[] =
4334 { UNUM_DECIMAL, UNUM_CURRENCY, UNUM_PATTERN_DECIMAL, UNUM_FORMAT_STYLE_COUNT };
4335 static const char* values[] =
4336 { "123.4", "234.5", "345.6", "456.7", NULL };
4337 static const UChar* pattern = u"#";
4338#if U_PLATFORM_IS_DARWIN_BASED
4339 mach_timebase_info_data_t info;
4340 mach_timebase_info(&info);
4341#endif
4342 const char** localesPtr = locales;
4343 const char* locale;
4344 while ((locale = *localesPtr++) != NULL) {
4345 const UNumberFormatStyle* stylesPtr = styles;
4346 UNumberFormatStyle style;
4347 while ((style = *stylesPtr++) < UNUM_FORMAT_STYLE_COUNT) {
4348#if !U_PLATFORM_HAS_WIN32_API
4349 uint64_t start, duration;
4350#else
4351 unsigned long long start, duration;
4352#endif
4353 UErrorCode status = U_ZERO_ERROR;
4354 const UChar* patternPtr = (style == UNUM_PATTERN_DECIMAL)? pattern: NULL;
4355 int32_t patternLen = (style == UNUM_PATTERN_DECIMAL)? u_strlen(pattern): 0;
4356 UNumberFormat *unum;
4357
4358 start = GET_START();
4359 unum = unum_open(style, patternPtr, patternLen, locale, NULL, &status);
4360 duration = GET_DURATION(start, info);
4361 log_info("== start locale %s, style %d\n", locale, (int)style);
4362 if ( U_FAILURE(status) ) {
4363 log_data_err("unum_open fails with %s\n", u_errorName(status));
4364 } else {
4365 log_info("unum_open nsec %5llu\n", duration);
4366 const char** valuesPtr = values;
4367 const char* value;
4368 while ((value = *valuesPtr++) != NULL) {
4369 UChar ubuf[kUBufMax];
4370 char bbuf[kBBufMax];
4371 int32_t ulen;
4372
4373 status = U_ZERO_ERROR;
4374 start = GET_START();
4375 ulen = unum_formatDecimal(unum, value, strlen(value), ubuf, kUBufMax, NULL, &status);
4376 duration = GET_DURATION(start, info);
4377 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4378 if ( U_FAILURE(status) ) {
4379 log_err("unum_formatDecimal %s fails with %s\n", value, u_errorName(status));
4380 } else {
4381 log_info("unum_formatDecimal %s, nsec %5llu, result %s\n", value, duration, bbuf);
4382 }
4383 }
4384 unum_close(unum);
4385 }
4386 }
4387 }
4388}
4389
4390
4391
4392
4393
4394#endif /* APPLE_ADDITIONS */
4395
4396#endif /* #if !UCONFIG_NO_FORMATTING */