]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/cintltst/cnumtst.c
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cnumtst.c
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/********************************************************************
4 * COPYRIGHT:
2ca993e8 5 * Copyright (c) 1997-2016, International Business Machines Corporation and
b75a7d8f
A
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"
729e4ab9 29#include "unicode/umisc.h"
b75a7d8f 30#include "unicode/unum.h"
57a6839d 31#include "unicode/unumsys.h"
b75a7d8f 32#include "unicode/ustring.h"
57a6839d 33#include "unicode/udisplaycontext.h"
c5116b9f 34#include "unicode/uchar.h"
729e4ab9 35
b75a7d8f
A
36#include "cintltst.h"
37#include "cnumtst.h"
38#include "cmemory.h"
57a6839d 39#include "cstring.h"
374ca955 40#include "putilimp.h"
3d1f044b 41#include "uassert.h"
51004dcb 42#include <stdio.h>
57a6839d 43#include <stdlib.h>
b75a7d8f 44
3d1f044b
A
45#define APPLE_ADDITIONS 1
46
51004dcb
A
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
b75a7d8f 55void addNumForTest(TestNode** root);
46f4442e
A
56static void TestTextAttributeCrash(void);
57static void TestNBSPInPattern(void);
729e4ab9 58static void TestInt64Parse(void);
4388f060 59static void TestParseCurrency(void);
51004dcb
A
60static void TestMaxInt(void);
61static void TestNoExponent(void);
3d1f044b
A
62static void TestSignAlwaysShown(void);
63static void TestMinimumGroupingDigits(void);
64static void TestParseCaseSensitive(void);
57a6839d
A
65static void TestUFormattable(void);
66static void TestUNumberingSystem(void);
67static void TestCurrencyIsoPluralFormat(void);
68static void TestContext(void);
b331163b
A
69static void TestCurrencyUsage(void);
70static void TestCurrFmtNegSameAsPositive(void);
71static void TestVariousStylesAndAttributes(void);
f3c0d7a5
A
72static void TestParseCurrPatternWithDecStyle(void);
73static void TestFormatForFields(void);
0f5d89e8
A
74static void TestRBNFRounding(void);
75static void Test12052_NullPointer(void);
3d1f044b
A
76static void TestParseCases(void);
77static void TestSetMaxFracAndRoundIncr(void);
78static void TestIgnorePadding(void);
57a6839d 79static void TestParseAltNum(void);
2ca993e8 80static void TestParseCurrPatternWithDecStyle(void);
0f5d89e8 81static void TestFormatPrecision(void);
3d1f044b
A
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>
1a147d09 91static void TestMinIntMinFracZero(void); // Apple <rdar://problem/54569257>
3d1f044b
A
92#if APPLE_ADDITIONS
93static void TestFormatDecPerf(void); // Apple <rdar://problem/51672521>
94#endif
b75a7d8f 95
374ca955
A
96#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
97
b75a7d8f
A
98void addNumForTest(TestNode** root)
99{
374ca955 100 TESTCASE(TestNumberFormat);
46f4442e 101 TESTCASE(TestSpelloutNumberParse);
374ca955 102 TESTCASE(TestSignificantDigits);
729e4ab9 103 TESTCASE(TestSigDigRounding);
374ca955
A
104 TESTCASE(TestNumberFormatPadding);
105 TESTCASE(TestInt64Format);
106 TESTCASE(TestNonExistentCurrency);
73c04bcf 107 TESTCASE(TestCurrencyRegression);
46f4442e 108 TESTCASE(TestTextAttributeCrash);
374ca955 109 TESTCASE(TestRBNFFormat);
0f5d89e8 110 TESTCASE(TestRBNFRounding);
46f4442e 111 TESTCASE(TestNBSPInPattern);
729e4ab9
A
112 TESTCASE(TestInt64Parse);
113 TESTCASE(TestParseZero);
4388f060 114 TESTCASE(TestParseCurrency);
4388f060 115 TESTCASE(TestCloneWithRBNF);
51004dcb
A
116 TESTCASE(TestMaxInt);
117 TESTCASE(TestNoExponent);
3d1f044b
A
118 TESTCASE(TestSignAlwaysShown);
119 TESTCASE(TestMinimumGroupingDigits);
120 TESTCASE(TestParseCaseSensitive);
57a6839d
A
121 TESTCASE(TestUFormattable);
122 TESTCASE(TestUNumberingSystem);
123 TESTCASE(TestCurrencyIsoPluralFormat);
124 TESTCASE(TestContext);
b331163b
A
125 TESTCASE(TestCurrencyUsage);
126 TESTCASE(TestCurrFmtNegSameAsPositive);
127 TESTCASE(TestVariousStylesAndAttributes);
f3c0d7a5
A
128 TESTCASE(TestParseCurrPatternWithDecStyle);
129 TESTCASE(TestFormatForFields);
3d1f044b
A
130 TESTCASE(Test12052_NullPointer);
131 TESTCASE(TestParseCases);
132 TESTCASE(TestSetMaxFracAndRoundIncr);
133 TESTCASE(TestIgnorePadding);
51004dcb 134 TESTCASE(TestParseAltNum);
2ca993e8 135 TESTCASE(TestParseCurrPatternWithDecStyle);
0f5d89e8 136 TESTCASE(TestFormatPrecision);
3d1f044b
A
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>
1a147d09 146 TESTCASE(TestMinIntMinFracZero); // Apple <rdar://problem/54569257>
3d1f044b
A
147#if APPLE_ADDITIONS
148 TESTCASE(TestFormatDecPerf); // Apple <rdar://problem/51672521>
149#endif
b75a7d8f
A
150}
151
729e4ab9
A
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);
57a6839d 181 (void)a; /* Suppress set but not used warning. */
729e4ab9
A
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
b75a7d8f
A
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;
73c04bcf 212 double d1 = -1.0;
b75a7d8f
A
213 int32_t l1;
214 double d = -10456.37;
374ca955 215 double a = 1234.56, a1 = 1235.0;
b75a7d8f
A
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);
73c04bcf
A
235
236 /* Might as well pack it in now if we can't even get a default NumberFormat... */
b75a7d8f 237 if(U_FAILURE(status))
73c04bcf 238 {
729e4ab9 239 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status));
73c04bcf
A
240 return;
241 }
b75a7d8f
A
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))
729e4ab9 259 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n",
b75a7d8f
A
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;
4388f060 314 pos1.field = UNUM_INTEGER_FIELD;
b75a7d8f
A
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
51004dcb 341 free(result);
b75a7d8f
A
342 result = 0;
343
344 log_verbose("\nTesting unum_formatDouble()\n");
57a6839d 345 u_uastrcpy(temp1, "-$10,456.37");
b75a7d8f 346 resultlength=0;
4388f060 347 pos2.field = UNUM_FRACTION_FIELD;
b75a7d8f
A
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 }
73c04bcf 363 if(result && u_strcmp(result, temp1)==0)
b75a7d8f 364 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n");
57a6839d
A
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 }
b75a7d8f
A
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++)*/
51004dcb
A
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");
73c04bcf 384 }
51004dcb
A
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));
b75a7d8f
A
387 }
388
389 if(d1!=d)
390 log_err("Fail: Error in parsing\n");
391 else
392 log_verbose("Pass: parsing successful\n");
374ca955
A
393 if (result)
394 free(result);
395 result = 0;
396
51004dcb 397 status = U_ZERO_ERROR;
374ca955
A
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;
4388f060 404 pos2.field = UNUM_INTEGER_FIELD;
374ca955
A
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)) {
57a6839d 413 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status));
374ca955
A
414 }
415 if (result && u_strcmp(result, temp1)==0) {
57a6839d 416 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n");
374ca955 417 } else {
57a6839d
A
418 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n",
419 aescstrdup(result, -1), aescstrdup(temp1, -1));
374ca955
A
420 }
421 if (pos2.beginIndex == 1 && pos2.endIndex == 6) {
422 log_verbose("Pass: Complete number formatting using unum_format() successful\n");
423 } else {
73c04bcf 424 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n",
374ca955
A
425 pos1.beginIndex, pos1.endIndex);
426 }
427
428 log_verbose("\nTesting unum_parseDoubleCurrency\n");
429 parsepos=0;
73c04bcf
A
430 if (result == NULL) {
431 log_err("result is NULL\n");
374ca955 432 }
73c04bcf
A
433 else {
434 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status);
435 if (U_FAILURE(status)) {
51004dcb 436 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status));
73c04bcf
A
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 {
57a6839d 442 log_verbose("Pass: parsed currency amount successfully\n");
73c04bcf
A
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 }
374ca955 449 }
51004dcb 450 status = U_ZERO_ERROR; /* reset */
374ca955 451
51004dcb 452 free(result);
374ca955
A
453 result = 0;
454
b75a7d8f
A
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 {
51004dcb 466 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1, resultlength), myErrorName(status));
b75a7d8f
A
467 }
468
729e4ab9
A
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)
b75a7d8f
A
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 }
729e4ab9 649 /* TODO:
b75a7d8f
A
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) {
2ca993e8 678 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
b75a7d8f
A
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*/
2ca993e8 688 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status);
b75a7d8f
A
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
729e4ab9 738 if(u_strcmp(prefix, temp)!=0)
b75a7d8f
A
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 }
729e4ab9 754 if(u_strcmp(prefix, temp)!=0)
b75a7d8f
A
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 }
729e4ab9 771 if(u_strcmp(suffix, temp)!=0)
b75a7d8f
A
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 }
729e4ab9 788 if(u_strcmp(suffix, temp)!=0)
b75a7d8f
A
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
b75a7d8f
A
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
374ca955
A
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)
0f5d89e8
A
818 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
819 unum_getAttribute(def,attr));
374ca955
A
820 else
821 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
822
b75a7d8f
A
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 };
2ca993e8 840 for (i = 0; i < UPRV_LENGTHOF(values); ++i) {
b75a7d8f
A
841 UChar buffer[128];
842 int32_t len;
843 int32_t value = values[i];
844 status = U_ZERO_ERROR;
2ca993e8 845 len = unum_format(spellout_def, value, buffer, UPRV_LENGTHOF(buffer), NULL, &status);
b75a7d8f
A
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;
2ca993e8 851 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/
51004dcb 852 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len);
b75a7d8f
A
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
729e4ab9
A
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";
3d1f044b
A
894 const char *parseExpected = "1.234567890098765432112345679E+19";
895 const char *parseExpected2 = "3.4567890098765432112345679E+17";
729e4ab9
A
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
4388f060 926 fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
729e4ab9
A
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 }
0f5d89e8 953 if (uprv_strcmp(parseExpected, desta) != 0) {
729e4ab9
A
954 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
955 __FILE__, __LINE__, parseExpected, desta);
0f5d89e8
A
956 } else {
957 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
958 __FILE__, __LINE__, desta);
729e4ab9
A
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 }
3d1f044b 975 if (strcmp(parseExpected2, desta) != 0) { /* "3.4567890098765432112345679E+17" */
729e4ab9 976 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
0f5d89e8
A
977 __FILE__, __LINE__, parseExpected2, desta);
978 } else {
979 log_verbose("File %s, Line %d, got expected = \"%s\"\n",
980 __FILE__, __LINE__, desta);
729e4ab9
A
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
4388f060
A
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
729e4ab9 1020
b75a7d8f
A
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
729e4ab9
A
1035static void TestParseZero(void)
1036{
1037 UErrorCode errorCode = U_ZERO_ERROR;
4388f060
A
1038 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */
1039 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */
729e4ab9
A
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)) {
4388f060 1050 log_data_err("Result - %s\n", u_errorName(errorCode));
729e4ab9
A
1051 } else {
1052 log_verbose("Double: %f\n", dbl);
1053 }
4388f060
A
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 */
f3c0d7a5 1059static const UChar dollarsUS4Sym[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */
4388f060
A
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[] = {
0f5d89e8
A
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, "" },
3d1f044b 1098 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" },
0f5d89e8
A
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" },
3d1f044b 1105 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 2, 0.0, U_PARSE_ERROR, 2, 0.0, "" },
0f5d89e8
A
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, "" },
3d1f044b 1108
0f5d89e8 1109 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL }
4388f060
A
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)) {
0f5d89e8 1126 const UChar * currStr = itemPtr->currStr;
4388f060
A
1127 status = U_ZERO_ERROR;
1128 parsePos = 0;
0f5d89e8 1129 parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status);
4388f060
A
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;
0f5d89e8 1139 parseVal = unum_parseDoubleCurrency(unum, currStr, -1, &parsePos, parseCurr, &status);
4388f060
A
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
4388f060
A
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) {
0f5d89e8 1161 log_err("UNUM_CURRENCY parseDouble Plural %s/%s, expect %s val %.1f, get %s val %.1f\n",
4388f060
A
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) {
0f5d89e8 1173 log_err("UNUM_CURRENCY parseDoubleCurrency Plural %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n",
4388f060
A
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 }
4388f060 1183 }
729e4ab9
A
1184}
1185
46f4442e
A
1186typedef struct {
1187 const char * testname;
1188 const char * locale;
729e4ab9 1189 UBool lenient;
46f4442e
A
1190 const UChar * source;
1191 int32_t startPos;
1192 int32_t value;
1193 int32_t endPos;
1194 UErrorCode status;
729e4ab9
A
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 */
f3c0d7a5
A
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 },
729e4ab9
A
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}
46f4442e
A
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,
729e4ab9
A
1235 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79,
1236 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */
57a6839d
A
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 */
46f4442e 1239static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */
729e4ab9
A
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 },
2ca993e8 1268 // from ICU50m2, NUMERIC_STRINGS_NOT_PARSEABLE no longer affects the next three
729e4ab9
A
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 },
729e4ab9
A
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 },
51004dcb 1275 { "zh,50dL","zh", TRUE, ustr_zh50d, 0, 50, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
729e4ab9 1276 { "zh,05aL","zh", TRUE, ustr_zh05a, 0, 0, 1, U_ZERO_ERROR },
51004dcb 1277 { "zh,05dL","zh", TRUE, ustr_zh05d, 0, 5, 2, U_ZERO_ERROR }, /* changed in ICU50m2 */
729e4ab9 1278 { NULL, NULL, FALSE, NULL, 0, 0, 0, 0 } /* terminator */
46f4442e
A
1279};
1280
1281static void TestSpelloutNumberParse()
1282{
729e4ab9 1283 const NumParseTestItem * testPtr;
46f4442e
A
1284 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) {
1285 UErrorCode status = U_ZERO_ERROR;
b331163b 1286 int32_t value, position = testPtr->startPos;
46f4442e
A
1287 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status);
1288 if (U_FAILURE(status)) {
729e4ab9 1289 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status));
46f4442e
A
1290 continue;
1291 }
729e4ab9 1292 unum_setAttribute(nf, UNUM_LENIENT_PARSE, testPtr->lenient);
f3c0d7a5 1293 status = U_ZERO_ERROR;
46f4442e
A
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
374ca955
A
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#");
0f5d89e8 1316 fmt=unum_open(UNUM_IGNORE, temp, -1, "en", NULL, &status);
374ca955 1317 if (U_FAILURE(status)) {
4388f060 1318 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status));
46f4442e 1319 return;
374ca955
A
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
729e4ab9
A
1347static void TestSigDigRounding()
1348{
1349 UErrorCode status = U_ZERO_ERROR;
1350 UChar expected[128];
1351 UChar result[128];
b331163b
A
1352 char temp1[128];
1353 char temp2[128];
729e4ab9
A
1354 UNumberFormat* fmt;
1355 double d = 123.4;
1356
0f5d89e8 1357 fmt=unum_open(UNUM_DECIMAL, NULL, 0, "en", NULL, &status);
729e4ab9
A
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
2ca993e8 1370 (void)unum_formatDouble(fmt, d, result, UPRV_LENGTHOF(result), NULL, &status);
729e4ab9
A
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
b75a7d8f
A
1384static void TestNumberFormatPadding()
1385{
1386 UChar *result=NULL;
1387 UChar temp1[512];
0f5d89e8 1388 UChar temp2[512];
b75a7d8f
A
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 {
729e4ab9 1406 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) );
b75a7d8f
A
1407 }
1408 else
1409 {
1410 unum_close(pattern);
1411 }
1412
1413/* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
0f5d89e8 1414 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
3d1f044b 1415 u_uastrcpy(temp2, "*x#########,##0.0#;(#########,##0.0#)"); // equivalent (?) output pattern
b75a7d8f
A
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 {
729e4ab9 1420 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );;
b75a7d8f
A
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 {
0f5d89e8
A
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 {
b75a7d8f 1449 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
0f5d89e8 1450 }
b75a7d8f 1451 }
0f5d89e8 1452 free(result);
b75a7d8f
A
1453/* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
1454 u_uastrcpy(temp1, "xxxxx(10,456.37)");
1455 resultlength=0;
4388f060 1456 pos1.field = UNUM_FRACTION_FIELD;
b75a7d8f
A
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
729e4ab9 1474 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n");
b75a7d8f
A
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
374ca955
A
1502static UBool
1503withinErr(double a, double b, double err) {
729e4ab9 1504 return uprv_fabs(a - b) < uprv_fabs(a * err);
374ca955
A
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;
729e4ab9 1514 const double doubleBig = 10.0 * (double)U_INT64_MAX;
374ca955
A
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");
f3c0d7a5 1523 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), "en_US", NULL, &status);
374ca955 1524 if(U_FAILURE(status)) {
4388f060 1525 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status));
374ca955
A
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 }
b331163b
A
1623
1624 u_uastrcpy(result, "5.06e-27");
4388f060
A
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 }
374ca955
A
1632 }
1633 unum_close(fmt);
1634}
1635
1636
1637static void test_fmt(UNumberFormat* fmt, UBool isDecimal) {
1638 char temp[512];
1639 UChar buffer[512];
2ca993e8 1640 int32_t BUFSIZE = UPRV_LENGTHOF(buffer);
374ca955
A
1641 double vals[] = {
1642 -.2, 0, .2, 5.5, 15.2, 250, 123456789
1643 };
1644 int i;
1645
2ca993e8 1646 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
374ca955
A
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);
4388f060 1671 if (isLenient != FALSE) {
374ca955
A
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);
4388f060 1677 if (isLenient != TRUE) {
374ca955
A
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 {
2ca993e8 1736 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) {
374ca955
A
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)) {
729e4ab9 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));
374ca955
A
1790 }
1791 else {
1792 unum_getSymbol(format,
1793 UNUM_CURRENCY_SYMBOL,
1794 currencySymbol,
2ca993e8 1795 UPRV_LENGTHOF(currencySymbol),
374ca955
A
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];
2ca993e8 1810 int COUNT = UPRV_LENGTHOF(formats);
374ca955
A
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)) {
729e4ab9
A
1822 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status));
1823 return;
374ca955
A
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)) {
729e4ab9
A
1829 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
1830 return;
374ca955
A
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)) {
729e4ab9
A
1836 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status));
1837 return;
374ca955
A
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)) {
729e4ab9
A
1843 log_err_status(status, "unable to open duration %s\n", u_errorName(status));
1844 return;
374ca955
A
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)) {
729e4ab9 1887 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status));
46f4442e
A
1888 }
1889 if (U_FAILURE(status)) {
729e4ab9 1890 log_err_status(status, "Something failed with %s\n", u_errorName(status));
46f4442e 1891 return;
374ca955
A
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
4388f060
A
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
374ca955
A
1916 for (i = 0; i < COUNT; ++i) {
1917 unum_close(formats[i]);
1918 }
1919}
1920
0f5d89e8
A
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);
3d1f044b 1932 U_ASSERT(len < FORMAT_BUF_CAPACITY);
0f5d89e8
A
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);
3d1f044b 1952 U_ASSERT(len < FORMAT_BUF_CAPACITY);
0f5d89e8
A
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
73c04bcf 1965static void TestCurrencyRegression(void) {
729e4ab9 1966/*
73c04bcf
A
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);
729e4ab9 1994
73c04bcf 1995 if(U_FAILURE(status)) {
729e4ab9 1996 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status));
73c04bcf
A
1997 return;
1998 }
729e4ab9 1999
73c04bcf
A
2000 status = U_ZERO_ERROR; /* so we can test it later. */
2001 pos = 0;
729e4ab9 2002
73c04bcf
A
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 }
729e4ab9 2018
73c04bcf
A
2019 unum_close(cur);
2020}
2021
46f4442e
A
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};
729e4ab9 2026 int32_t used;
46f4442e 2027 UErrorCode status = U_ZERO_ERROR;
729e4ab9 2028 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
46f4442e 2029 if (U_FAILURE(status)) {
729e4ab9 2030 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status));
46f4442e
A
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");
729e4ab9 2044 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status);
46f4442e
A
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 }
729e4ab9 2052 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status);
46f4442e
A
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
51004dcb 2063static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) {
46f4442e
A
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);
51004dcb 2069 log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString));
46f4442e 2070 if(U_FAILURE(status)) {
51004dcb 2071 log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status));
46f4442e
A
2072 return;
2073 }
2074 aNumber = unum_parse(nf, myString, -1, NULL, &status);
2075 if(U_FAILURE(status)) {
51004dcb 2076 log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status));
46f4442e
A
2077 return;
2078 }
2079 if(uprv_fabs(aNumber-myNumber)>.001) {
51004dcb 2080 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
46f4442e 2081 } else {
51004dcb 2082 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber);
46f4442e
A
2083 }
2084}
2085
2086static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) {
51004dcb
A
2087 TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.);
2088 TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.);
46f4442e
A
2089}
2090
2091static void TestNBSPInPattern(void) {
2092 UErrorCode status = U_ZERO_ERROR;
2093 UNumberFormat* nf = NULL;
2094 const char *testcase;
729e4ab9
A
2095
2096
46f4442e
A
2097 testcase="ar_AE UNUM_CURRENCY";
2098 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status);
729e4ab9 2099 if(U_FAILURE(status) || nf == NULL) {
51004dcb 2100 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status));
729e4ab9 2101 return;
46f4442e
A
2102 }
2103 TestNBSPPatternRT(testcase, nf);
729e4ab9 2104
46f4442e
A
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;
2ca993e8 2110 u_unescape(SPECIAL_PATTERN, pat, UPRV_LENGTHOF(pat));
46f4442e 2111 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status);
729e4ab9 2112 if(U_FAILURE(status)) {
46f4442e
A
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;
729e4ab9 2120
46f4442e
A
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;
729e4ab9 2128
46f4442e
A
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));
729e4ab9
A
2133 }
2134 TestNBSPPatternRT(testcase, nf);
46f4442e 2135 unum_close(nf); status = U_ZERO_ERROR;
729e4ab9
A
2136
2137
2138
46f4442e 2139}
3d1f044b 2140static void TestCloneWithRBNF(void) {
4388f060
A
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;");
46f4442e 2186
4388f060
A
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}
51004dcb
A
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
0f5d89e8 2281 // A scientific formatter should parse the exponent even if UNUM_PARSE_NO_EXPONENT is set
51004dcb
A
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 */
0f5d89e8 2309 "en",
51004dcb
A
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
3d1f044b
A
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
57a6839d
A
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 },
0f5d89e8 2561 { "ar-EG", "arab", 10, FALSE, arabDesc },
57a6839d
A
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;
3d1f044b 2575
57a6839d
A
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 }
3d1f044b
A
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 }
57a6839d 2621 }
3d1f044b
A
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));
57a6839d 2629 }
57a6839d
A
2630 }
2631}
2632
2633/* plain-C version of test in numfmtst.cpp */
3d1f044b 2634enum { kUBufMax = 64, kBBufMax = 128 };
57a6839d 2635static void TestCurrencyIsoPluralFormat(void) {
2ca993e8 2636 static const char* DATA[][8] = {
57a6839d
A
2637 // the data are:
2638 // locale,
2639 // currency amount to be formatted,
2640 // currency ISO code to be formatted,
2641 // format result using CURRENCYSTYLE,
2ca993e8
A
2642 // format result using CURRENCY_STANDARD,
2643 // format result using CURRENCY_ACCOUNTING,
57a6839d
A
2644 // format result using ISOCURRENCYSTYLE,
2645 // format result using PLURALCURRENCYSTYLE,
2646
3d1f044b
A
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"},
2ca993e8
A
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
3d1f044b
A
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"},
c5116b9f 2672 {"id_ID", "1234.56", "IDR", "Rp1.235", "Rp1.235", "Rp1.235", "IDR\\u00A01.235", "1.235 Rupiah Indonesia"},
57a6839d 2673 // test locale without currency information
2ca993e8
A
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"},
57a6839d 2676 // test choice format
2ca993e8 2677 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
57a6839d
A
2678 };
2679 static const UNumberFormatStyle currencyStyles[] = {
2680 UNUM_CURRENCY,
2ca993e8
A
2681 UNUM_CURRENCY_STANDARD,
2682 UNUM_CURRENCY_ACCOUNTING,
57a6839d
A
2683 UNUM_CURRENCY_ISO,
2684 UNUM_CURRENCY_PLURAL
2685 };
2686
2687 int32_t i, sIndex;
3d1f044b
A
2688
2689 for (i=0; i<UPRV_LENGTHOF(DATA); ++i) {
57a6839d
A
2690 const char* localeString = DATA[i][0];
2691 double numberToBeFormat = atof(DATA[i][1]);
2692 const char* currencyISOCode = DATA[i][2];
2ca993e8 2693 for (sIndex = 0; sIndex < UPRV_LENGTHOF(currencyStyles); ++sIndex) {
57a6839d
A
2694 UNumberFormatStyle style = currencyStyles[sIndex];
2695 UErrorCode status = U_ZERO_ERROR;
3d1f044b 2696 UChar currencyCode[4] = {0};
57a6839d
A
2697 UChar ubufResult[kUBufMax];
2698 UChar ubufExpected[kUBufMax];
2699 int32_t ulenRes;
3d1f044b
A
2700 const char* currencyISOCodeForLog = currencyISOCode;
2701
57a6839d
A
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 }
3d1f044b
A
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 }
57a6839d 2714 if (U_FAILURE(status)) {
3d1f044b 2715 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString, currencyISOCodeForLog, myErrorName(status));
57a6839d
A
2716 }
2717 ulenRes = unum_formatDouble(unumFmt, numberToBeFormat, ubufResult, kUBufMax, NULL, &status);
2718 if (U_FAILURE(status)) {
3d1f044b 2719 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s: %s\n", localeString, currencyISOCodeForLog, myErrorName(status));
57a6839d
A
2720 } else {
2721 int32_t ulenExp = u_unescape(DATA[i][3 + sIndex], ubufExpected, kUBufMax);
2722 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
3d1f044b
A
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);
57a6839d
A
2729 }
2730 }
2731 unum_close(unumFmt);
2732 }
3d1f044b 2733 }
57a6839d
A
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;
3d1f044b 2759
57a6839d
A
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;
3d1f044b 2780
57a6839d
A
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];
3d1f044b 2798 u_austrncpy(bbuf, ubufResult, sizeof(bbuf));
57a6839d
A
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
b331163b
A
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
2ca993e8 2816 * - CAD rounds to .05
b331163b
A
2817 */
2818
3d1f044b 2819 {"PKR", "PKR\\u00A0124"},
2ca993e8 2820 {"CAD", "CA$123.55"},
b331163b
A
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
3d1f044b 2857 for (j=0; j<UPRV_LENGTHOF(DATA); ++j) {
b331163b
A
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);
2ca993e8 2866 expectLen = u_unescape(DATA[j][1], expect, UPRV_LENGTHOF(expect));
b331163b
A
2867
2868 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status);
2869 assertSuccess("num_setTextAttribute()", &status);
2870
2ca993e8 2871 resultLen = unum_formatDouble(unumFmt, numberToBeFormat, result, UPRV_LENGTHOF(result),
b331163b
A
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 }
3d1f044b 2881
b331163b
A
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
3d1f044b
A
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;
b331163b
A
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;
3d1f044b 2938 const char *valueStr;
b331163b
A
2939 const char *expected;
2940} ValueAndExpectedString;
2941
3d1f044b
A
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};
b331163b 2953static const ValueAndExpectedString enShort[] = {
3d1f044b
A
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}
b331163b
A
2971};
2972
2973static const ValueAndExpectedString enShortMax2[] = {
3d1f044b
A
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}
b331163b
A
2991};
2992
2993static const ValueAndExpectedString enShortMax5[] = {
3d1f044b
A
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}
b331163b
A
3011};
3012
3013static const ValueAndExpectedString enShortMin3[] = {
3d1f044b
A
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}
b331163b
A
3031};
3032
3033static const ValueAndExpectedString jaShortMax2[] = {
3d1f044b
A
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}
b331163b
A
3047};
3048
3049static const ValueAndExpectedString srLongMax2[] = {
3d1f044b
A
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}
b331163b
A
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[] = {
3d1f044b 3088 { "en", UNUM_DECIMAL, UNUM_MIN_FRACTION_DIGITS, 1, enDecMinFrac },
b331163b
A
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 },
3d1f044b 3095 { NULL, (UNumberFormatStyle)0, -1, 0, NULL }
b331163b
A
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) ) {
2ca993e8 3104 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr->style, lsaTestPtr->locale, u_errorName(status));
b331163b
A
3105 } else {
3106 const ValueAndExpectedString * veItemPtr;
3107 if (lsaTestPtr->attribute >= 0) {
3108 unum_setAttribute(unum, (UNumberFormatAttribute)lsaTestPtr->attribute, lsaTestPtr->attrValue);
3109 }
0f5d89e8
A
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 }
b331163b
A
3114 for (veItemPtr = lsaTestPtr->veItems; veItemPtr->expected != NULL; veItemPtr++) {
3115 UChar uexp[kUBufSize];
3116 UChar uget[kUBufSize];
3117 int32_t uexplen, ugetlen;
3d1f044b 3118
b331163b
A
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 }
3d1f044b
A
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 }
b331163b
A
3146 }
3147 unum_close(unum);
3148 }
3149 }
3150}
3151
2ca993e8
A
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)) {
f3c0d7a5 3168 log_err_status(status, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status), value);
2ca993e8
A
3169 }
3170 }
3171 unum_close(unumfmt);
3172 }
3173}
3174
f3c0d7a5
A
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};
a01113dc 3205/* "en_US"/"es_US/MX" , UNUM_PERCENT, -34 : "#,##0%" => "-34%" */
f3c0d7a5
A
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 },
a01113dc
A
3230 { "es_US", UNUM_PERCENT, -0.34, fields_en_PRCT }, // rdar://57000745
3231 { "es_MX", UNUM_PERCENT, -0.34, fields_en_PRCT }, // rdar://42948387
f3c0d7a5
A
3232 { "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR },
3233 { "en_US", UNUM_PATTERN_DECIMAL, 12.0, fields_en_PATN },
3234 { NULL, (UNumberFormatStyle)0, 0, NULL },
3235};
3236
3237static void TestFormatForFields(void) {
3238 UErrorCode status = U_ZERO_ERROR;
3239 UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
3240 if ( U_FAILURE(status) ) {
3241 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status));
3242 } else {
3243 const FormatForFieldsItem * itemPtr;
3244 for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) {
3245 UNumberFormat* unum;
3246 status = U_ZERO_ERROR;
3247 unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)?
3248 unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status):
3249 unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
3250 if ( U_FAILURE(status) ) {
3251 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));
3252 } else {
3253 UChar ubuf[kUBufSize];
3254 int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status);
3255 if ( U_FAILURE(status) ) {
3256 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3257 } else {
3258 const FieldsData * fptr;
3259 int32_t field, beginPos, endPos;
3260 for (fptr = itemPtr->expectedFields; TRUE; fptr++) {
3261 field = ufieldpositer_next(fpositer, &beginPos, &endPos);
3262 if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) {
3263 if (fptr->field >= 0) {
3264 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n",
3265 itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos);
3266 } else {
3267 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n",
3268 itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos);
3269 }
3270 break;
3271 }
3272 if (field < 0) {
3273 break;
3274 }
3275 }
3276 }
3277 unum_close(unum);
3278 }
3279 }
3280 ufieldpositer_close(fpositer);
3281 }
3282}
3283
0f5d89e8
A
3284static void Test12052_NullPointer() {
3285 UErrorCode status = U_ZERO_ERROR;
3286 static const UChar input[] = u"199a";
3287 UChar currency[200] = {0};
3288 UNumberFormat *theFormatter = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
3289 if (!assertSuccessCheck("unum_open() failed", &status, TRUE)) { return; }
3290 status = U_ZERO_ERROR;
3291 unum_setAttribute(theFormatter, UNUM_LENIENT_PARSE, 1);
3292 int32_t pos = 1;
3293 unum_parseDoubleCurrency(theFormatter, input, -1, &pos, currency, &status);
3294 assertEquals("should fail gracefully", "U_PARSE_ERROR", u_errorName(status));
3295 unum_close(theFormatter);
3296}
3297
3298typedef struct {
3299 const char* locale;
3300 const UChar* text; // text to parse
3301 UBool lenient; // leniency to use
3d1f044b 3302 UBool intOnly; // whether to set PARSE_INT_ONLY
0f5d89e8
A
3303 UErrorCode intStatus; // expected status from parse
3304 int32_t intPos; // expected final pos from parse
3305 int32_t intValue; // expected value from parse
3306 UErrorCode doubStatus; // expected status from parseDouble
3307 int32_t doubPos; // expected final pos from parseDouble
3308 double doubValue; // expected value from parseDouble
3d1f044b
A
3309 UErrorCode decStatus; // expected status from parseDecimal
3310 int32_t decPos; // expected final pos from parseDecimal
3311 const char* decString; // expected output string from parseDecimal
3312
0f5d89e8
A
3313} ParseCaseItem;
3314
3315static const ParseCaseItem parseCaseItems[] = {
3d1f044b
A
3316 { "en", u"0,000", FALSE, FALSE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0, U_ZERO_ERROR, 5, "0" },
3317 { "en", u"0,000", TRUE, FALSE, U_ZERO_ERROR, 5, 0, U_ZERO_ERROR, 5, 0.0, U_ZERO_ERROR, 5, "0" },
3318 { "en", u",024", FALSE, FALSE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0, U_ZERO_ERROR, 4, "24" },
3319 { "en", u",024", TRUE, FALSE, U_ZERO_ERROR, 4, 24, U_ZERO_ERROR, 4, 24.0, U_ZERO_ERROR, 4, "24" },
3320 { "en", u"1000,000", FALSE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3321 { "en", u"1000,000", TRUE, FALSE, U_ZERO_ERROR, 8, 1000000, U_ZERO_ERROR, 8, 1000000.0, U_ZERO_ERROR, 8, "1000000" },
3322 { "en", u"", FALSE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3323 { "en", u"", TRUE, FALSE, U_PARSE_ERROR, 0, 0, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, "" },
3324 { "en", u"9999990000503021", FALSE, FALSE, U_INVALID_FORMAT_ERROR, 16, 2147483647, U_ZERO_ERROR, 16, 9999990000503020.0, U_ZERO_ERROR, 16, "9999990000503021" },
3325 { "en", u"9999990000503021", FALSE, TRUE, U_INVALID_FORMAT_ERROR, 16, 2147483647, U_ZERO_ERROR, 16, 9999990000503020.0, U_ZERO_ERROR, 16, "9999990000503021" },
3326 { "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 */},
3327 { "en", u"1000000.5", FALSE, TRUE, U_ZERO_ERROR, 7, 1000000, U_ZERO_ERROR, 7, 1000000.0, U_ZERO_ERROR, 7, "1000000" },
3328 { "en", u"123.5", FALSE, FALSE, U_ZERO_ERROR, 5, 123, U_ZERO_ERROR, 5, 123.5, U_ZERO_ERROR, 5, "123.5" },
3329 { "en", u"123.5", FALSE, TRUE, U_ZERO_ERROR, 3, 123, U_ZERO_ERROR, 3, 123.0, U_ZERO_ERROR, 3, "123" },
3330 { NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, NULL }
0f5d89e8
A
3331};
3332
0f5d89e8
A
3333static void TestParseCases(void) {
3334 const ParseCaseItem* itemPtr;
3335 for (itemPtr = parseCaseItems; itemPtr->locale != NULL; itemPtr++) {
3336 UErrorCode status = U_ZERO_ERROR;
3337 UNumberFormat* unumDec = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status);
3338 if (U_FAILURE(status)) {
3339 log_data_err("unum_open UNUM_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3340 continue;
3341 }
3d1f044b 3342 int32_t intValue, parsePos, dclen;
0f5d89e8 3343 double doubValue;
3d1f044b 3344 char decstr[32];
0f5d89e8 3345 unum_setAttribute(unumDec, UNUM_LENIENT_PARSE, itemPtr->lenient);
3d1f044b 3346 unum_setAttribute(unumDec, UNUM_PARSE_INT_ONLY, itemPtr->intOnly);
0f5d89e8
A
3347
3348 parsePos = 0;
3349 status = U_ZERO_ERROR;
3350 intValue = unum_parse(unumDec, itemPtr->text, -1, &parsePos, &status);
3351 if (status != itemPtr->intStatus || parsePos != itemPtr->intPos || intValue != itemPtr->intValue) {
3352 char btext[32];
3353 u_austrcpy(btext, itemPtr->text);
3d1f044b
A
3354 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",
3355 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3356 u_errorName(itemPtr->intStatus), itemPtr->intPos, itemPtr->intValue,
0f5d89e8
A
3357 u_errorName(status), parsePos, intValue);
3358 }
3359
3360 parsePos = 0;
3361 status = U_ZERO_ERROR;
3362 doubValue = unum_parseDouble(unumDec, itemPtr->text, -1, &parsePos, &status);
3363 if (status != itemPtr->doubStatus || parsePos != itemPtr->doubPos || doubValue != itemPtr->doubValue) {
3364 char btext[32];
3365 u_austrcpy(btext, itemPtr->text);
3d1f044b
A
3366 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",
3367 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3368 u_errorName(itemPtr->doubStatus), itemPtr->doubPos, itemPtr->doubValue,
0f5d89e8
A
3369 u_errorName(status), parsePos, doubValue);
3370 }
3d1f044b
A
3371
3372 parsePos = 0;
3373 status = U_ZERO_ERROR;
3374 decstr[0] = 0;
3375 dclen = unum_parseDecimal(unumDec, itemPtr->text, -1, &parsePos, decstr, 32, &status);
3376 if (status != itemPtr->decStatus || parsePos != itemPtr->decPos || uprv_strcmp(decstr,itemPtr->decString) != 0) {
3377 char btext[32];
3378 u_austrcpy(btext, itemPtr->text);
3379 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",
3380 itemPtr->locale, btext, itemPtr->lenient, itemPtr->intOnly,
3381 u_errorName(itemPtr->decStatus), itemPtr->decPos, itemPtr->decString,
3382 u_errorName(status), parsePos, decstr);
3383 }
3384
3385 unum_close(unumDec);
3386 }
3387}
3388
3389typedef struct {
3390 const char* descrip;
3391 const char* locale;
3392 UNumberFormatStyle style;
3393 int32_t minInt;
3394 int32_t minFrac;
3395 int32_t maxFrac;
3396 double roundIncr;
3397 const UChar* expPattern;
3398 double valueToFmt;
3399 const UChar* expFormat;
3400} SetMaxFracAndRoundIncrItem;
3401
3402static const SetMaxFracAndRoundIncrItem maxFracAndRoundIncrItems[] = {
3403 // descrip locale style mnI mnF mxF rdInc expPat value expFmt
3404 { "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" },
3405 { "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" },
3406 { "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" },
3407 { "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" },
3408 { "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
3409 { "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
3410
3411 { "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" },
3412 { "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
3413 { "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
3414 { "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" },
3415 { "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
3416 { "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
3417 { "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
3418 { "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
3419 { "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
3420
3421 { "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" },
3422 { "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
3423 { "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
3424 { "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
3425 { "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
3426 { "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
3427 { "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
3428 { "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
3429 { "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
3430 { "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
3431 { "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
3432
3433 // Additions for rdar://51452216
3434 { "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" },
3435 { "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" },
3436
3437 { NULL, NULL, UNUM_IGNORE, 0, 0, 0, 0.0, NULL, 0.0, NULL }
3438};
3439
3440// The following is copied from C++ number_patternstring.cpp for this C test.
3441//
3442// Determine whether a given roundingIncrement should be ignored for formatting
3443// based on the current maxFrac value (maximum fraction digits). For example a
3444// roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
3445// is 2 or more. Note that roundingIncrements are rounded in significance, so
3446// a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
3447// it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
3448// 0.005 is treated like 0.001 for significance). This is the reason for the
3449// initial doubling below.
3450// roundIncr must be non-zero
3451static UBool ignoreRoundingIncrement(double roundIncr, int32_t maxFrac) {
3452 if (maxFrac < 0) {
3453 return FALSE;
3454 }
3455 int32_t frac = 0;
3456 roundIncr *= 2.0;
3457 for (frac = 0; frac <= maxFrac && roundIncr <= 1.0; frac++, roundIncr *= 10.0);
3458 return (frac > maxFrac);
3459}
3460
3461static void TestSetMaxFracAndRoundIncr(void) {
3462 const SetMaxFracAndRoundIncrItem* itemPtr;
3463 for (itemPtr = maxFracAndRoundIncrItems; itemPtr->descrip != NULL; itemPtr++) {
3464 UChar ubuf[kUBufMax];
3465 char bbufe[kBBufMax];
3466 char bbufg[kBBufMax];
3467 int32_t ulen;
3468 UErrorCode status = U_ZERO_ERROR;
3469 UNumberFormat* unf = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
3470 if (U_FAILURE(status)) {
3471 log_data_err("locale %s: unum_open style %d fails with %s\n", itemPtr->locale, itemPtr->style, u_errorName(status));
3472 continue;
3473 }
3474
3475 unum_setAttribute(unf, UNUM_MIN_INTEGER_DIGITS, itemPtr->minInt);
3476 unum_setAttribute(unf, UNUM_MIN_FRACTION_DIGITS, itemPtr->minFrac);
3477 unum_setAttribute(unf, UNUM_MAX_FRACTION_DIGITS, itemPtr->maxFrac);
3478 unum_setDoubleAttribute(unf, UNUM_ROUNDING_INCREMENT, itemPtr->roundIncr);
3479
3480 UBool roundIncrUsed = (itemPtr->roundIncr != 0.0 && !ignoreRoundingIncrement(itemPtr->roundIncr, itemPtr->maxFrac));
3481
3482 int32_t minInt = unum_getAttribute(unf, UNUM_MIN_INTEGER_DIGITS);
3483 if (minInt != itemPtr->minInt) {
3484 log_err("test %s: unum_getAttribute UNUM_MIN_INTEGER_DIGITS, expected %d, got %d\n",
3485 itemPtr->descrip, itemPtr->minInt, minInt);
3486 }
3487 int32_t minFrac = unum_getAttribute(unf, UNUM_MIN_FRACTION_DIGITS);
3488 if (minFrac != itemPtr->minFrac) {
3489 log_err("test %s: unum_getAttribute UNUM_MIN_FRACTION_DIGITS, expected %d, got %d\n",
3490 itemPtr->descrip, itemPtr->minFrac, minFrac);
3491 }
3492 // If incrementRounding is used, maxFrac is set equal to minFrac
3493 int32_t maxFrac = unum_getAttribute(unf, UNUM_MAX_FRACTION_DIGITS);
3494 // If incrementRounding is used, maxFrac is set equal to minFrac
3495 int32_t expMaxFrac = (roundIncrUsed)? itemPtr->minFrac: itemPtr->maxFrac;
3496 if (maxFrac != expMaxFrac) {
3497 log_err("test %s: unum_getAttribute UNUM_MAX_FRACTION_DIGITS, expected %d, got %d\n",
3498 itemPtr->descrip, expMaxFrac, maxFrac);
3499 }
3500 double roundIncr = unum_getDoubleAttribute(unf, UNUM_ROUNDING_INCREMENT);
3501 // If incrementRounding is not used, roundIncr is set to 0.0
3502 double expRoundIncr = (roundIncrUsed)? itemPtr->roundIncr: 0.0;
3503 if (roundIncr != expRoundIncr) {
3504 log_err("test %s: unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT, expected %f, got %f\n",
3505 itemPtr->descrip, expRoundIncr, roundIncr);
3506 }
3507
3508 status = U_ZERO_ERROR;
3509 ulen = unum_toPattern(unf, FALSE, ubuf, kUBufMax, &status);
3510 if ( U_FAILURE(status) ) {
3511 log_err("test %s: unum_toPattern fails with %s\n", itemPtr->descrip, u_errorName(status));
3512 } else if (u_strcmp(ubuf,itemPtr->expPattern)!=0) {
3513 u_austrcpy(bbufe, itemPtr->expPattern);
3514 u_austrcpy(bbufg, ubuf);
3515 log_err("test %s: unum_toPattern expect \"%s\", get \"%s\"\n", itemPtr->descrip, bbufe, bbufg);
3516 }
3517
3518 status = U_ZERO_ERROR;
3519 ulen = unum_formatDouble(unf, itemPtr->valueToFmt, ubuf, kUBufMax, NULL, &status);
3520 if ( U_FAILURE(status) ) {
3521 log_err("test %s: unum_formatDouble fails with %s\n", itemPtr->descrip, u_errorName(status));
3522 } else if (u_strcmp(ubuf,itemPtr->expFormat)!=0) {
3523 u_austrcpy(bbufe, itemPtr->expFormat);
3524 u_austrcpy(bbufg, ubuf);
3525 log_err("test %s: unum_formatDouble expect \"%s\", get \"%s\"\n", itemPtr->descrip, bbufe, bbufg);
3526 }
3527
3528 unum_close(unf);
3529 }
3530}
3531
3532static void TestIgnorePadding(void) {
3533 UErrorCode status = U_ZERO_ERROR;
3534 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
3535 if (U_FAILURE(status)) {
3536 log_data_err("unum_open UNUM_PATTERN_DECIMAL for en_US and NULL pattern fails:%s\n", u_errorName(status));
3537 } else {
3538 unum_setAttribute(unum, UNUM_GROUPING_USED, 0);
3539 unum_setAttribute(unum, UNUM_FORMAT_WIDTH, 0);
3540 unum_setTextAttribute(unum, UNUM_PADDING_CHARACTER, u"*", 1, &status);
3541 if (U_FAILURE(status)) {
3542 log_err("unum_setTextAttribute UNUM_PADDING_CHARACTER to '*' fails: %s\n", u_errorName(status));
3543 } else {
3544 unum_setAttribute(unum, UNUM_PADDING_POSITION, 0);
3545 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
3546 unum_setAttribute(unum, UNUM_MAX_INTEGER_DIGITS, 8);
3547 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
3548 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 0);
3549
3550 UChar ubuf[kUBufMax];
3551 int32_t ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
3552 if (U_FAILURE(status)) {
3553 log_err("unum_toPattern fails: %s\n", u_errorName(status));
3554 } else {
3555 char bbuf[kBBufMax];
3556 if (ulen > 0 && ubuf[0]==u'*') {
3557 ubuf[kUBufMax-1] = 0; // ensure zero termination
3558 u_austrncpy(bbuf, ubuf, kBBufMax);
3559 log_err("unum_toPattern result should ignore padding but get %s\n", bbuf);
3560 }
3561 unum_applyPattern(unum, FALSE, ubuf, ulen, NULL, &status);
3562 if (U_FAILURE(status)) {
3563 log_err("unum_applyPattern fails: %s\n", u_errorName(status));
3564 } else {
3565 ulen = unum_formatDecimal(unum, "24", -1, ubuf, kUBufMax, NULL, &status);
3566 if (U_FAILURE(status)) {
3567 log_err("unum_formatDecimal fails: %s\n", u_errorName(status));
3568 } else if (u_strcmp(ubuf, u"24") != 0) {
3569 ubuf[kUBufMax-1] = 0; // ensure zero termination
3570 u_austrncpy(bbuf, ubuf, kBBufMax);
3571 log_err("unum_formatDecimal result expect 24 but get %s\n", bbuf);
3572 }
3573 }
3574 }
3575 }
3576 unum_close(unum);
0f5d89e8
A
3577 }
3578}
3579
3580typedef struct {
3581 const char* locale;
3582 double value;
3583 const UChar* formatLimitPrecision;
3584 const UChar* formatFullPrecision;
3585} FormatPrecisionItem;
3586
3587static const FormatPrecisionItem formatPrecisionItems[] = {
3588 { "en_US", 0.33333333 - 0.00333333, u"0.33", u"0.32999999999999996" },
3589 { "en_US", 0.07 * 100.0, u"7", u"7.000000000000001" },
3590 { NULL, 0.0, NULL, NULL }
3591};
3592
3593static const UChar* patternTestPrecision = u"#0.################################################################################"; // 80 fraction places
3594
3595// Currently Apple only
3596static void TestFormatPrecision(void) {
3597 const FormatPrecisionItem* itemPtr;
3598 for (itemPtr = formatPrecisionItems; itemPtr->locale != NULL; itemPtr++) {
3599 UErrorCode status = U_ZERO_ERROR;
3600 UParseError perr;
3601 UNumberFormat *unum = unum_open(UNUM_PATTERN_DECIMAL, patternTestPrecision, -1, itemPtr->locale, &perr, &status);
3602 if (U_FAILURE(status)) {
3603 log_data_err("unum_open UNUM_PATTERN_DECIMAL fails for locale %s: %s\n", itemPtr->locale, u_errorName(status));
3604 continue;
3605 }
3d1f044b
A
3606 UChar ubuf[kUBufSize];
3607 int32_t ulen;
3608 UFieldPosition fpos;
3609 UBool formatFullPrecision;
0f5d89e8
A
3610
3611 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3612 if (formatFullPrecision) {
3613 log_err("unum_getAttribute, default for UNUM_FORMAT_WITH_FULL_PRECISION is not FALSE\n");
3614 } else {
3d1f044b
A
3615 fpos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
3616 fpos.beginIndex = 0;
3617 fpos.endIndex = 0;
0f5d89e8
A
3618 status = U_ZERO_ERROR;
3619 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3620 if (U_FAILURE(status)) {
3621 log_err("unum_formatDouble locale %s val %.20f limit precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3622 } else if (ulen != u_strlen(itemPtr->formatLimitPrecision) || u_strcmp(ubuf, itemPtr->formatLimitPrecision) != 0) {
3d1f044b
A
3623 char bbufe[kBBufSize];
3624 char bbufg[kBBufSize];
0f5d89e8
A
3625 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatLimitPrecision, -1, &status);
3626 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3627 log_err("unum_formatDouble locale %s val %.20f limit precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3628 }
3629 }
3630
3631 unum_setAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION, TRUE);
3632 formatFullPrecision = (UBool)unum_getAttribute(unum, UNUM_FORMAT_WITH_FULL_PRECISION);
3633 if (!formatFullPrecision) {
3634 log_err("unum_getAttribute, after set UNUM_FORMAT_WITH_FULL_PRECISION is not TRUE\n");
3635 } else {
3d1f044b
A
3636 fpos.field = UNUM_DECIMAL_SEPARATOR_FIELD;
3637 fpos.beginIndex = 0;
3638 fpos.endIndex = 0;
0f5d89e8
A
3639 status = U_ZERO_ERROR;
3640 ulen = unum_formatDouble(unum, itemPtr->value, ubuf, kUBufSize, &fpos, &status);
3641 if (U_FAILURE(status)) {
3642 log_err("unum_formatDouble locale %s val %.20f full precision fails with %s\n", itemPtr->locale, itemPtr->value, u_errorName(status));
3643 } else if (ulen != u_strlen(itemPtr->formatFullPrecision) || u_strcmp(ubuf, itemPtr->formatFullPrecision) != 0) {
3d1f044b
A
3644 char bbufe[kBBufSize];
3645 char bbufg[kBBufSize];
0f5d89e8
A
3646 u_strToUTF8(bbufe, kBBufSize, NULL, itemPtr->formatFullPrecision, -1, &status);
3647 u_strToUTF8(bbufg, kBBufSize, NULL, ubuf, ulen, &status);
3648 log_err("unum_formatDouble locale %s val %.20f full precision, expect %s, get %s\n", itemPtr->locale, itemPtr->value, bbufe, bbufg);
3649 }
3650 }
3651
3652 unum_close(unum);
3653 }
3654}
3655
3d1f044b
A
3656// Apple only for <rdar://problem/52538227>
3657static void TestSetSigDigAndRoundIncr(void) {
3658 UErrorCode status = U_ZERO_ERROR;
3659 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, u"#", 1, "en_US", NULL, &status);
3660 if ( U_FAILURE(status) ) {
3661 log_data_err("unum_open UNUM_PATTERN_DECIMAL # for \"en_US\" fails with %s\n", u_errorName(status));
3662 } else {
3663 static const double value = 1.034000;
3664 UChar ubuf[kUBufMax];
3665 char bbuf[kBBufMax];
3666 int32_t ulen;
3667
3668 unum_setAttribute(unum, UNUM_MAX_INTEGER_DIGITS, 42);
3669 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 0);
3670 unum_setAttribute(unum, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP); // =6
3671 unum_setDoubleAttribute(unum, UNUM_ROUNDING_INCREMENT, 0.01);
3672 unum_setAttribute(unum, UNUM_SIGNIFICANT_DIGITS_USED, 1);
3673 unum_setAttribute(unum, UNUM_MAX_SIGNIFICANT_DIGITS, 5);
3674 unum_setAttribute(unum, UNUM_MIN_SIGNIFICANT_DIGITS, 1);
3675
3676 log_info("unum_getAttribute minSig %d maxSig %d sigUsed %d\n",
3677 unum_getAttribute(unum,UNUM_MIN_SIGNIFICANT_DIGITS), unum_getAttribute(unum,UNUM_MAX_SIGNIFICANT_DIGITS),
3678 unum_getAttribute(unum,UNUM_SIGNIFICANT_DIGITS_USED));
3679 log_info("unum_getDoubleAttribute UNUM_ROUNDING_INCREMENT %f\n", unum_getDoubleAttribute(unum,UNUM_SIGNIFICANT_DIGITS_USED));
3680 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
3681 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
3682 if ( U_SUCCESS(status) ) {
3683 log_info("unum_toPattern (%d): %s\n", ulen, bbuf);
3684 }
3685
3686 status = U_ZERO_ERROR;
3687 ulen = unum_formatDouble(unum, value, ubuf, kUBufMax, NULL, &status);
3688 if ( U_FAILURE(status) ) {
c5116b9f 3689 log_err("unum_formatDouble value %.1f status %s\n", value, u_errorName(status));
3d1f044b
A
3690 } else if (u_strcmp(ubuf,u"1.03") != 0) {
3691 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
3692 log_err("unum_formatDouble value %.1f expected 1.03, got %s\n", value, bbuf);
3693 }
3694 unum_close(unum);
3695 }
3696}
3697
3698// Apple for <rdar://problem/46755430>
3699typedef struct {
3700 const char* descrip;
3701 const char* locale;
3702 const UChar* setPosPrefix;
3703 const UChar* setPosSuffix;
3704 const UChar* setNegPrefix;
3705 const UChar* setNegSuffix;
3706 const UChar* expPosPrefix;
3707 const UChar* expPosSuffix;
3708 const UChar* expNegPrefix;
3709 const UChar* expNegSuffix;
3710 const UChar* expPattern;
3711 double value;
3712 const UChar* expPosFormat;
3713 const UChar* expNegFormat;
3714} SetAffixOnCurrFmtItem;
3715
3716static const SetAffixOnCurrFmtItem affixOnCurrFmtItems[] = {
3717 // descrip loc sPP sPS sNP sNS ePP ePS eNP eNS ePattern value ePosFmt eNegFmt
3718 { "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" },
3719 { "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" },
3720 { "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" },
3721 { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.0,NULL,NULL }
3722};
3723
3724// Apple only for <rdar://problem/46755430>
3725static void TestSetAffixOnCurrFmt(void) {
3726 const SetAffixOnCurrFmtItem* itemPtr;
3727 for (itemPtr = affixOnCurrFmtItems; itemPtr->descrip != NULL; itemPtr++) {
3728 UChar ubuf[kUBufMax];
3729 char bbufe[kBBufMax];
3730 char bbufg[kBBufMax];
3731 int32_t ulen;
3732 UErrorCode status = U_ZERO_ERROR;
3733 UNumberFormat* unf = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
3734 if (U_FAILURE(status)) {
3735 log_data_err("locale %s: unum_open UNUM_CURRENCY fails with %s\n", itemPtr->locale, u_errorName(status));
3736 continue;
3737 }
3738
3739 if (itemPtr->setPosPrefix) {
3740 status = U_ZERO_ERROR;
3741 unum_setTextAttribute(unf, UNUM_POSITIVE_PREFIX, itemPtr->setPosPrefix, -1, &status);
3742 if (U_FAILURE(status)) {
3743 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3744 }
3745 }
3746 if (itemPtr->setPosSuffix) {
3747 status = U_ZERO_ERROR;
3748 unum_setTextAttribute(unf, UNUM_POSITIVE_SUFFIX, itemPtr->setPosSuffix, -1, &status);
3749 if (U_FAILURE(status)) {
3750 log_err("test %s: unum_setTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3751 }
3752 }
3753 if (itemPtr->setNegPrefix) {
3754 status = U_ZERO_ERROR;
3755 unum_setTextAttribute(unf, UNUM_NEGATIVE_PREFIX, itemPtr->setNegPrefix, -1, &status);
3756 if (U_FAILURE(status)) {
3757 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3758 }
3759 }
3760 if (itemPtr->setNegSuffix) {
3761 status = U_ZERO_ERROR;
3762 unum_setTextAttribute(unf, UNUM_NEGATIVE_SUFFIX, itemPtr->setNegSuffix, -1, &status);
3763 if (U_FAILURE(status)) {
3764 log_err("test %s: unum_setTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3765 }
3766 }
3767
3768 status = U_ZERO_ERROR;
3769 ulen = unum_getTextAttribute(unf, UNUM_POSITIVE_PREFIX, ubuf, kUBufMax, &status);
3770 if (U_FAILURE(status)) {
3771 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3772 } else if (u_strcmp(ubuf,itemPtr->expPosPrefix)!=0) {
3773 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosPrefix, -1, &status);
3774 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3775 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_PREFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3776 }
3777 status = U_ZERO_ERROR;
3778 ulen = unum_getTextAttribute(unf, UNUM_POSITIVE_SUFFIX, ubuf, kUBufMax, &status);
3779 if (U_FAILURE(status)) {
3780 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3781 } else if (u_strcmp(ubuf,itemPtr->expPosSuffix)!=0) {
3782 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosSuffix, -1, &status);
3783 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3784 log_err("test %s: unum_getTextAttribute UNUM_POSITIVE_SUFFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3785 }
3786 status = U_ZERO_ERROR;
3787 ulen = unum_getTextAttribute(unf, UNUM_NEGATIVE_PREFIX, ubuf, kUBufMax, &status);
3788 if (U_FAILURE(status)) {
3789 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3790 } else if (u_strcmp(ubuf,itemPtr->expNegPrefix)!=0) {
3791 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegPrefix, -1, &status);
3792 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3793 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_PREFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3794 }
3795 status = U_ZERO_ERROR;
3796 ulen = unum_getTextAttribute(unf, UNUM_NEGATIVE_SUFFIX, ubuf, kUBufMax, &status);
3797 if (U_FAILURE(status)) {
3798 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX fails with %s\n", itemPtr->descrip, u_errorName(status));
3799 } else if (u_strcmp(ubuf,itemPtr->expNegSuffix)!=0) {
3800 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegSuffix, -1, &status);
3801 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3802 log_err("test %s: unum_getTextAttribute UNUM_NEGATIVE_SUFFIX expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3803 }
3804 status = U_ZERO_ERROR;
3805 ulen = unum_toPattern(unf, FALSE, ubuf, kUBufMax, &status);
3806 if (U_FAILURE(status)) {
3807 log_err("test %s: unum_toPattern fails with %s\n", itemPtr->descrip, u_errorName(status));
3808 } else if (u_strcmp(ubuf,itemPtr->expPattern)!=0) {
3809 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPattern, -1, &status);
3810 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3811 log_err("test %s: unum_toPattern expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3812 }
3813
3814 status = U_ZERO_ERROR;
3815 ulen = unum_formatDouble(unf, itemPtr->value, ubuf, kUBufMax, NULL, &status);
3816 if (U_FAILURE(status)) {
3817 log_err("test %s: unum_formatDouble positive fails with %s\n", itemPtr->descrip, u_errorName(status));
3818 } else if (u_strcmp(ubuf,itemPtr->expPosFormat)!=0) {
3819 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expPosFormat, -1, &status);
3820 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3821 log_err("test %s: unum_formatDouble positive expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3822 }
3823 status = U_ZERO_ERROR;
3824 ulen = unum_formatDouble(unf, -1.0*itemPtr->value, ubuf, kUBufMax, NULL, &status);
3825 if (U_FAILURE(status)) {
3826 log_err("test %s: unum_formatDouble negative fails with %s\n", itemPtr->descrip, u_errorName(status));
3827 } else if (u_strcmp(ubuf,itemPtr->expNegFormat)!=0) {
3828 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expNegFormat, -1, &status);
3829 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
3830 log_err("test %s: unum_formatDouble negative expect %s, get %s\n", itemPtr->descrip, bbufe, bbufg);
3831 }
3832
3833 unum_close(unf);
3834 }
3835}
3836
3837// Apple only for <rdar://problem/46915356>
3838static void TestParseWithEmptyCurr(void) {
3839 UErrorCode status = U_ZERO_ERROR;
3840 UNumberFormat* unum = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
3841 if (U_FAILURE(status)) {
3842 log_data_err("unum_open UNUM_CURRENCY for \"en_US\" fails with %s\n", u_errorName(status));
3843 } else {
3844 unum_setSymbol(unum, UNUM_CURRENCY_SYMBOL, u"", 0, &status);
3845 if (U_FAILURE(status)) {
3846 log_err("unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s\n", u_errorName(status));
3847 } else {
3848 char bbuf[kBBufMax] = { 0 };
3849 UChar curr[4] = { 0 };
3850 int32_t ppos, blen;
3851 double val;
3852 const UChar* text = u"3";
3853
3854 status = U_ZERO_ERROR;
3855 ppos = 0;
3856 blen = unum_parseDecimal(unum, text, -1, &ppos, bbuf, kBBufMax, &status);
3857 if (U_FAILURE(status)) {
3858 log_err("unum_parseDecimal u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status), ppos);
3859 } else if (ppos != 1 || blen != 1 || bbuf[0] != '3') {
3860 log_err("unum_parseDecimal expect ppos 1, blen 1, str 3; get %d, %d, %s\n", ppos, blen, bbuf);
3861 }
3862
3863 status = U_ZERO_ERROR;
3864 ppos = 0;
3865 val = unum_parseDouble(unum, text, -1, &ppos, &status);
3866 if (U_FAILURE(status)) {
3867 log_err("unum_parseDouble u\"3\" with empty curr symbol fails with %s, ppos %d\n", u_errorName(status), ppos);
3868 } else if (ppos != 1 || val != 3.0) {
3869 log_err("unum_parseDouble expect ppos 1, val 3.0; get %d, %.2f\n", ppos, val);
3870 }
3871
3872 status = U_ZERO_ERROR;
3873 ppos = 0;
3874 val = unum_parseDoubleCurrency(unum, text, -1, &ppos, curr, &status);
3875 if (U_SUCCESS(status)) {
3876 log_err("unum_parseDoubleCurrency u\"3\" with empty curr symbol succeeds, get ppos %d, val %.2f\n", ppos, val);
3877 }
3878 }
3879 unum_close(unum);
3880 }
c5116b9f
A
3881
3882 // Additions for <rdar://problem/51938595>
3883 // "¤#,##0.00" "¤ #,##0.00" "#,##0.00 ¤" "#,##,##0.00¤"
3884 static const char* locales[] = {"en_US", "en_NO", "en_CZ", "en_BD", NULL };
3885 const char ** localesPtr = locales;
3886 const char* locale;
3887 while ((locale = *localesPtr++) != NULL) {
3888 status = U_ZERO_ERROR;
3889 unum = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status);
3890 if (U_FAILURE(status)) {
3891 log_data_err("locale %s unum_open UNUM_CURRENCY fails with %s\n", locale, u_errorName(status));
3892 } else {
3893 char bbuf[kBBufMax] = { 0 };
3894 UChar curr[4] = { 0 };
3895 UChar ubuf[kUBufMax];
3896 int32_t ppos, blen, ulen;
3897 const double posValToUse = 37.0;
3898 const double negValToUse = -3.0;
3899 double val;
3900
3901 status = U_ZERO_ERROR;
3902 unum_setSymbol(unum, UNUM_CURRENCY_SYMBOL, u"", 0, &status);
3903 if (U_FAILURE(status)) {
3904 log_err("locale %s unum_setSymbol UNUM_CURRENCY_SYMBOL u\"\" fails with %s, skipping\n", locale, u_errorName(status));
3905 continue;
3906 }
3907
3908 status = U_ZERO_ERROR;
3909 ulen = unum_formatDouble(unum, posValToUse, ubuf, kUBufMax, NULL, &status);
3910 if (U_FAILURE(status)) {
3911 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale, posValToUse, u_errorName(status));
3912 continue;
3913 }
3914
3915 status = U_ZERO_ERROR;
3916 ppos = 0;
3917 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3918 if (U_FAILURE(status)) {
3919 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, posValToUse);
3920 } else if (ppos != ulen || val != posValToUse) {
3921 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, posValToUse, ppos, val);
3922 }
3923
3924 status = U_ZERO_ERROR;
3925 ulen = unum_formatDouble(unum, negValToUse, ubuf, kUBufMax, NULL, &status);
3926 if (U_FAILURE(status)) {
3927 log_err("locale %s unum_formatDouble %.1f fails with %s, skipping\n", locale, negValToUse, u_errorName(status));
3928 continue;
3929 }
3930
3931 status = U_ZERO_ERROR;
3932 ppos = 0;
3933 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3934 if (U_FAILURE(status)) {
3935 log_err("locale %s unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, negValToUse);
3936 } else if (ppos != ulen || val != negValToUse) {
3937 log_err("locale %s unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, negValToUse, ppos, val);
3938 }
3939
3940 status = U_ZERO_ERROR;
3941 unum_applyPattern(unum, FALSE, u"#,##0.00¤", -1, NULL, &status);
3942 if (U_FAILURE(status)) {
3943 log_err("locale %s unum_applyPattern \"#,##0.00¤\" fails with %s, skipping\n", locale, u_errorName(status));
3944 continue;
3945 }
3946
3947 status = U_ZERO_ERROR;
3948 ulen = unum_formatDouble(unum, posValToUse, ubuf, kUBufMax, NULL, &status);
3949 if (U_FAILURE(status)) {
3950 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale, posValToUse, u_errorName(status));
3951 continue;
3952 }
3953
3954 status = U_ZERO_ERROR;
3955 ppos = 0;
3956 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3957 if (U_FAILURE(status)) {
3958 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, posValToUse);
3959 } else if (ppos != ulen || val != posValToUse) {
3960 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, posValToUse, ppos, val);
3961 }
3962
3963 status = U_ZERO_ERROR;
3964 ulen = unum_formatDouble(unum, negValToUse, ubuf, kUBufMax, NULL, &status);
3965 if (U_FAILURE(status)) {
3966 log_err("locale %s with \"#,##0.00¤\" unum_formatDouble %.1f fails with %s, skipping\n", locale, negValToUse, u_errorName(status));
3967 continue;
3968 }
3969
3970 status = U_ZERO_ERROR;
3971 ppos = 0;
3972 val = unum_parseDouble(unum, ubuf, ulen, &ppos, &status);
3973 if (U_FAILURE(status)) {
3974 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble fails with %s, ppos %d, expect %.1f\n", locale, u_errorName(status), ppos, negValToUse);
3975 } else if (ppos != ulen || val != negValToUse) {
3976 log_err("locale %s with \"#,##0.00¤\" unum_parseDouble expect ppos %d, val %.1f; get %d, %.2f\n", locale, ulen, negValToUse, ppos, val);
3977 }
3978
3979 unum_close(unum);
3980 }
3981 }
3d1f044b
A
3982}
3983
3984// Apple only for <rdar://problem/50113359>
249c4c5e 3985static const UChar* pat1 = u"#.##E+00;-#.##E+00";
3d1f044b 3986static void TestSciNotationNumbers(void) {
249c4c5e
A
3987 UErrorCode status = U_ZERO_ERROR;
3988 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
3989 if ( U_FAILURE(status) ) {
3990 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status));
3991 } else {
3992 unum_applyPattern(unum, FALSE, pat1, u_strlen(pat1), NULL, &status);
3993 if ( U_FAILURE(status) ) {
3994 log_err("unum_applyPattern fails with %s\n", u_errorName(status));
3995 } else {
3996 double value;
3997 UChar ubuf[kUBufMax];
3998 char bbuf[kBBufMax];
3999 int32_t ulen;
4000
249c4c5e 4001 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
3d1f044b
A
4002 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 2147483647);
4003 log_info("unum_getAttribute minInt %d maxInt %d minFrac %d maxFrac %d\n",
4004 unum_getAttribute(unum,UNUM_MIN_INTEGER_DIGITS), unum_getAttribute(unum,UNUM_MAX_INTEGER_DIGITS),
4005 unum_getAttribute(unum,UNUM_MIN_FRACTION_DIGITS), unum_getAttribute(unum,UNUM_MAX_FRACTION_DIGITS));
4006 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
4007 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4008 if ( U_SUCCESS(status) ) {
4009 log_info("unum_toPattern (%d): %s\n", ulen, bbuf);
4010 }
249c4c5e 4011
3d1f044b 4012 for (value = 10.0; value < 1000000000.0; value *= 10.0) {
249c4c5e
A
4013 status = U_ZERO_ERROR;
4014 ulen = unum_formatDouble(unum, value, ubuf, kUBufMax, NULL, &status);
4015 if ( U_FAILURE(status) ) {
c5116b9f 4016 log_err("unum_formatDouble value %.1f status %s\n", value, u_errorName(status));
3d1f044b 4017 } else if (u_strncmp(ubuf,u"1E+0",4) != 0) {
249c4c5e 4018 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
3d1f044b 4019 log_err("unum_formatDouble value %.1f expected result to begin with 1E+0, got %s\n", value, bbuf);
249c4c5e
A
4020 }
4021 }
4022 }
4023 unum_close(unum);
4024 }
4025}
4026
3d1f044b
A
4027// Apple only for <rdar://problem/51601250>
4028static const UChar* patFmt3Exp = u"0.000E+00";
4029static void TestSciNotationPrecision(void) {
4030 UErrorCode status = U_ZERO_ERROR;
4031 UNumberFormat* unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_US", NULL, &status);
4032 if ( U_FAILURE(status) ) {
4033 log_data_err("unum_open UNUM_PATTERN_DECIMAL with null pattern for \"en_US\" fails with %s\n", u_errorName(status));
4034 } else {
4035 unum_applyPattern(unum, FALSE, pat1, u_strlen(pat1), NULL, &status);
4036 if ( U_FAILURE(status) ) {
4037 log_err("unum_applyPattern fails with %s\n", u_errorName(status));
4038 } else {
4039 double value;
4040 UChar ubuf[kUBufMax];
4041 char bexp[kBBufMax];
4042 char bget[kBBufMax];
4043 int32_t ulen;
4044
4045 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 3);
4046 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 3);
4047 unum_setAttribute(unum, UNUM_GROUPING_USED, 0);
4048
4049 status = U_ZERO_ERROR;
4050 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
4051 if ( U_FAILURE(status) ) {
4052 log_err("unum_toPattern fails with %s\n", u_errorName(status));
4053 } else if (u_strcmp(ubuf,patFmt3Exp) != 0) {
4054 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4055 log_info("unum_toPattern, get \"%s\"\n", bget);
4056 }
4057
4058 status = U_ZERO_ERROR;
4059 ulen = unum_formatDouble(unum, 0.0, ubuf, ulen, NULL, &status);
4060 if ( U_FAILURE(status) ) {
4061 log_err("unum_formatDouble fails with %s\n", u_errorName(status));
4062 } else if (u_strcmp(ubuf,patFmt3Exp) != 0) {
4063 u_strToUTF8(bexp, kBBufMax, NULL, patFmt3Exp, -1, &status);
4064 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4065 log_err("unum_formatDouble error, expect \"%s\", get \"%s\"\n", bexp, bget);
4066 }
4067 }
4068 unum_close(unum);
4069 }
4070}
4071
4072// Apple only for <rdar://problem/49808819>
4073static const char* minGroupLocale = "pt_PT"; // has minimumGroupingDigits{"2"}
4074typedef struct {
4075 double value;
4076 const char* string;
4077 const UChar* expectDecimal;
4078 const UChar* expectCurrency;
4079} TestMinGroupItem;
4080static const TestMinGroupItem minGroupItems[] = {
4081 { 123.0, "123.0", u"123,00", u"123,00 €" },
4082 { 1234.0, "1234.0", u"1234,00", u"1234,00 €" },
4083 { 12345.0, "12345.0", u"12 345,00", u"12 345,00 €" },
4084 { 123456.0, "123456.0", u"123 456,00", u"123 456,00 €" },
4085 { 1234567.0, "1234567.0", u"1 234 567,00", u"1 234 567,00 €" },
4086 { 12345678.0, "12345678.0", u"12 345 678,00", u"12 345 678,00 €" },
4087 { 0.0, NULL, NULL, NULL } // terminator
4088};
4089static void TestMinimumGrouping(void) {
4090 UErrorCode status = U_ZERO_ERROR;
4091 UNumberFormat* unumd = unum_open(UNUM_DECIMAL, NULL, 0, minGroupLocale, NULL, &status);
4092 UNumberFormat* unumc = unum_open(UNUM_CURRENCY, NULL, 0, minGroupLocale, NULL, &status);
4093 if ( U_FAILURE(status) ) {
4094 log_data_err("unum_open UNUM_PATTERN_DECIMAL/CURRENCY for %s fails with %s\n", minGroupLocale, u_errorName(status));
4095 } else {
4096 const TestMinGroupItem* itemPtr;
4097 unum_setAttribute(unumd, UNUM_MIN_FRACTION_DIGITS, 2);
4098 for (itemPtr = minGroupItems; itemPtr->value != 0.0; itemPtr++) {
4099 UChar ubuf[kUBufMax];
4100 char bbufe[kBBufMax];
4101 char bbufg[kBBufMax];
4102 int32_t ulen;
4103
4104 status = U_ZERO_ERROR;
4105 ulen = unum_formatDecimal(unumd, itemPtr->string, -1, ubuf, kUBufMax, NULL, &status);
4106 if ( U_FAILURE(status) ) {
4107 log_err("unum_formatDecimal DEC for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4108 } else if (u_strcmp(ubuf, itemPtr->expectDecimal) != 0) {
4109 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectDecimal, -1, &status);
4110 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4111 log_err("unum_formatDecimal DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4112 minGroupLocale, itemPtr->value, bbufe, bbufg);
4113 }
4114
4115 status = U_ZERO_ERROR;
4116 ulen = unum_formatDouble(unumd, itemPtr->value, ubuf, kUBufMax, NULL, &status);
4117 if ( U_FAILURE(status) ) {
4118 log_err("unum_formatDouble DEC for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4119 } else if (u_strcmp(ubuf, itemPtr->expectDecimal) != 0) {
4120 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectDecimal, -1, &status);
4121 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4122 log_err("unum_formatDouble DEC for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4123 minGroupLocale, itemPtr->value, bbufe, bbufg);
4124 }
4125
4126 status = U_ZERO_ERROR;
4127 ulen = unum_formatDouble(unumc, itemPtr->value, ubuf, kUBufMax, NULL, &status);
4128 if ( U_FAILURE(status) ) {
4129 log_err("unum_formatDouble CUR for locale %s, value %.1f fails with %s\n", minGroupLocale, itemPtr->value, u_errorName(status));
4130 } else if (u_strcmp(ubuf, itemPtr->expectCurrency) != 0) {
4131 u_strToUTF8(bbufe, kBBufMax, NULL, itemPtr->expectCurrency, -1, &status);
4132 u_strToUTF8(bbufg, kBBufMax, NULL, ubuf, ulen, &status);
4133 log_err("unum_formatDouble CUR for locale %s, value %.1f, expected \"%s\" but got \"%s\"\n",
4134 minGroupLocale, itemPtr->value, bbufe, bbufg);
4135 }
4136 }
4137 unum_close(unumc);
4138 unum_close(unumd);
4139 }
4140}
4141
4142// Apple only for <rdar://problem/49120648>
4143static const char* const numSysLocales[] = {
4144 "en_US", "en_US@numbers=arab", "en_US@numbers=roman", "en_US@numbers=grek", "en_US@numbers=hebr",
4145 "zh@numbers=hanidec", "zh_Hant@numbers=traditional", "en@numbers=finance", NULL
4146};
4147static void TestNumberSystemsMultiplier(void) {
4148 const char* const* localesPtr = numSysLocales;
4149 const char* locale;
4150 while ((locale = *localesPtr++) != NULL) {
4151 UErrorCode status = U_ZERO_ERROR;
4152 UNumberFormat *unum = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status);
4153 if ( U_FAILURE(status) ) {
4154 log_data_err("unum_open UNUM_DECIMAL for %s fails with %s\n", locale, u_errorName(status));
4155 } else {
4156 int32_t multiplier = unum_getAttribute(unum, UNUM_MULTIPLIER);
4157 log_info("for locale %s with UNUM_DECIMAL, UNUM_MULTIPLIER is %d\n", locale, multiplier);
4158 unum_close(unum);
4159 }
4160 }
4161}
4162
4163// Apple only for <rdar://problem/39156484>
4164typedef struct {
4165 const char* locale;
4166 const UChar* stringToParse;
4167 double expectValue;
4168 int32_t expectPos;
4169} ParseScientificItem;
4170static const ParseScientificItem parseSciItems[] = {
4171 { "en_US", u"4E\u200E+05", 400000.0, 6 },
4172 { "en_US", u"4E+05", 400000.0, 5 },
4173 { "en_US", u"4E\u200E-02", 0.04, 6 },
4174 { "en_US", u"4E-02", 0.04, 5 },
4175 { "he_IL", u"4E\u200E+05", 400000.0, 6 },
4176 { "he_IL", u"4E+05", 400000.0, 5 },
4177 { "he_IL", u"4E\u200E-02", 0.04, 6 },
4178 { "he_IL", u"4E-02", 0.04, 5 },
4179 { "en@numbers=arabext", u"\u06F4\u00D7\u06F1\u06F0^\u200E+\u200E\u06F0\u06F5", 400000.0, 10 },
4180 { "en@numbers=arabext", u"\u06F4\u00D7\u06F1\u06F0^+\u06F0\u06F5", 400000.0, 8 },
4181 { NULL,NULL, 0.0, 0 } // terminator
4182};
4183static void TestParseScientific(void) {
4184 const ParseScientificItem* itemPtr;
4185 for (itemPtr = parseSciItems; itemPtr->locale != NULL; itemPtr++) {
4186 UErrorCode status = U_ZERO_ERROR;
4187 UNumberFormat *unum = unum_open(UNUM_SCIENTIFIC, NULL, 0, itemPtr->locale, NULL, &status);
4188 if ( U_FAILURE(status) ) {
4189 log_data_err("unum_open UNUM_SCIENTIFIC for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4190 } else {
4191 int32_t parsePos = 0;
4192 double result = unum_parseDouble(unum, itemPtr->stringToParse, -1, &parsePos, &status);
4193 if ( U_FAILURE(status) ) {
4194 log_err("unum_parseDouble for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4195 } else if (result != itemPtr->expectValue || parsePos != itemPtr->expectPos) {
4196 log_err("unum_parseDouble for %s, expected result %.1f pos %d, got %.1f %d\n",
4197 itemPtr->locale, itemPtr->expectValue, itemPtr->expectPos, result, parsePos);
4198 }
4199 unum_close(unum);
4200 }
4201 }
4202}
4203
4204// Apple only for <rdar://problem/51985640>
4205typedef struct {
4206 const char* locale;
4207 const UChar* expCurrCode;
4208} LocaleCurrCodeItem;
4209static const LocaleCurrCodeItem currCodeItems[] = {
4210 { "en", u"" }, // curr ICU has "XXX"
4211 { "en@currency=EUR", u"EUR" },
4212 { "en_US", u"USD" },
4213 { "en_ZZ", u"XAG" },
4214 { "_US", u"USD" },
4215 { "_ZZ", u"XAG" },
4216 { "us", u"" }, // curr ICU has "XXX"
4217 { "", u"" }, // curr ICU has "XXX"
4218 { NULL, NULL }
4219};
4220static void TestCurrForUnkRegion(void) {
4221 const LocaleCurrCodeItem* itemPtr;
4222 for (itemPtr = currCodeItems; itemPtr->locale != NULL; itemPtr++) {
4223 UErrorCode status = U_ZERO_ERROR;
4224 UNumberFormat* unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status);
4225 if ( U_FAILURE(status) ) {
4226 log_data_err("unum_open UNUM_CURRENCY for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4227 } else {
4228 UChar ubuf[kUBufMax];
4229 int32_t ulen = unum_getTextAttribute(unum, UNUM_CURRENCY_CODE, ubuf, kUBufMax, &status);
4230 if ( U_FAILURE(status) ) {
4231 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4232 } else if (u_strcmp(ubuf,itemPtr->expCurrCode)!=0) {
4233 char bexp[kBBufMax];
4234 char bget[kBBufMax];
4235 u_strToUTF8(bexp, kBBufMax, NULL, itemPtr->expCurrCode, -1, &status);
4236 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4237 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect \"%s\" but get \"%s\"\n", itemPtr->locale, bexp, bget);
4238 }
4239 status = U_ZERO_ERROR;
4240 unum_setTextAttribute(unum, UNUM_CURRENCY_CODE, u"XXX", 3, &status);
4241 if ( U_FAILURE(status) ) {
4242 log_err("unum_setTextAttribute UNUM_CURRENCY_CODE for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4243 } else {
4244 ulen = unum_getTextAttribute(unum, UNUM_CURRENCY_CODE, ubuf, kUBufMax, &status);
4245 if ( U_FAILURE(status) ) {
4246 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE XXX for %s fails with %s\n", itemPtr->locale, u_errorName(status));
4247 } else if (u_strcmp(ubuf,u"XXX")!=0) {
4248 char bget[kBBufMax];
4249 u_strToUTF8(bget, kBBufMax, NULL, ubuf, ulen, &status);
4250 log_err("unum_getTextAttribute UNUM_CURRENCY_CODE error for %s, expect XXX but get \"%s\"\n", itemPtr->locale, bget);
4251 }
4252 }
4253 unum_close(unum);
4254 }
4255 }
4256}
4257
1a147d09 4258static void TestMinIntMinFracZero(void) {
a01113dc
A
4259 UChar ubuf[kUBufMax];
4260 char bbuf[kBBufMax];
4261 int minInt, minFrac, maxFrac, ulen;
4262
1a147d09
A
4263 UErrorCode status = U_ZERO_ERROR;
4264 UNumberFormat* unum = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
4265 if ( U_FAILURE(status) ) {
4266 log_data_err("unum_open UNUM_DECIMAL for en_US fails with %s\n", u_errorName(status));
4267 } else {
1a147d09
A
4268 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
4269 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
4270 minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
4271 minFrac = unum_getAttribute(unum, UNUM_MIN_FRACTION_DIGITS);
4272 if (minInt != 0 || minFrac != 0) {
4273 log_err("after setting minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt, minFrac);
4274 }
a01113dc 4275
1a147d09 4276 ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
a01113dc
A
4277 if ( U_FAILURE(status) ) {
4278 log_err("unum_toPattern fails with %s\n", u_errorName(status));
4279 } else if (ulen < 3 || u_strstr(ubuf, u"#.#")==NULL) {
1a147d09 4280 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
a01113dc 4281 log_err("after setting minInt=minFrac=0, expect pattern to contain \"#.#\", but get (%d): \"%s\"\n", ulen, bbuf);
1a147d09
A
4282 }
4283
4284 status = U_ZERO_ERROR;
4285 ulen = unum_formatDouble(unum, 10.0, ubuf, kUBufMax, NULL, &status);
4286 if ( U_FAILURE(status) ) {
4287 log_err("unum_formatDouble 10.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4288 } else if (u_strcmp(ubuf, u"10") != 0) {
4289 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4290 log_err("unum_formatDouble 10.0 expected \"10\", got \"%s\"\n", bbuf);
4291 }
4292
4293 status = U_ZERO_ERROR;
4294 ulen = unum_formatDouble(unum, 0.9, ubuf, kUBufMax, NULL, &status);
4295 if ( U_FAILURE(status) ) {
4296 log_err("unum_formatDouble 0.9 ulen %d fails with %s\n", ulen, u_errorName(status));
4297 } else if (u_strcmp(ubuf, u".9") != 0) {
4298 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4299 log_err("unum_formatDouble 0.9 expected \".9\", got \"%s\"\n", bbuf);
4300 }
4301
4302 status = U_ZERO_ERROR;
4303 ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
4304 if ( U_FAILURE(status) ) {
4305 log_err("unum_formatDouble 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4306 } else if (u_strcmp(ubuf, u"0") != 0) {
4307 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4308 log_err("unum_formatDouble 0.0 expected \"0\", got \"%s\"\n", bbuf);
4309 }
4310
4311 unum_close(unum);
4312 }
a01113dc
A
4313
4314 status = U_ZERO_ERROR;
4315 unum = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
4316 if ( U_FAILURE(status) ) {
4317 log_data_err("unum_open UNUM_CURRENCY for en_US fails with %s\n", u_errorName(status));
4318 } else {
4319 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
4320 unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
4321 minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
4322 minFrac = unum_getAttribute(unum, UNUM_MIN_FRACTION_DIGITS);
4323 if (minInt != 0 || minFrac != 0) {
4324 log_err("after setting CURRENCY minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt, minFrac);
4325 }
4326
4327 status = U_ZERO_ERROR;
4328 ulen = unum_formatDouble(unum, 10.0, ubuf, kUBufMax, NULL, &status);
4329 if ( U_FAILURE(status) ) {
4330 log_err("unum_formatDouble (CURRRENCY) 10.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4331 } else if (u_strcmp(ubuf, u"$10") != 0) {
4332 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4333 log_err("unum_formatDouble (CURRRENCY) 10.0 expected \"$10\", got \"%s\"\n", bbuf);
4334 }
4335
4336 status = U_ZERO_ERROR;
4337 ulen = unum_formatDouble(unum, 0.9, ubuf, kUBufMax, NULL, &status);
4338 if ( U_FAILURE(status) ) {
4339 log_err("unum_formatDouble (CURRRENCY) 0.9 ulen %d fails with %s\n", ulen, u_errorName(status));
4340 } else if (u_strcmp(ubuf, u"$.9") != 0) {
4341 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4342 log_err("unum_formatDouble (CURRRENCY) 0.9 expected \"$.9\", got \"%s\"\n", bbuf);
4343 }
4344
4345 status = U_ZERO_ERROR;
4346 ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
4347 if ( U_FAILURE(status) ) {
4348 log_err("unum_formatDouble (CURRRENCY) 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4349 } else if (u_strcmp(ubuf, u"$0") != 0) {
4350 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4351 log_err("unum_formatDouble (CURRRENCY) 0.0 expected \"$0\", got \"%s\"\n", bbuf);
4352 }
4353
4354 unum_close(unum);
4355 }
4356
4357 // addition for rdar://57291456
4358 status = U_ZERO_ERROR;
4359 unum = unum_open(UNUM_PATTERN_DECIMAL, NULL, 0, "en_IE", NULL, &status);
4360 if ( U_FAILURE(status) ) {
4361 log_data_err("unum_open UNUM_DECIMAL for en_US fails with %s\n", u_errorName(status));
4362 } else {
4363 unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
4364 unum_setAttribute(unum, UNUM_MAX_FRACTION_DIGITS, 1);
4365 minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
4366 maxFrac = unum_getAttribute(unum, UNUM_MAX_FRACTION_DIGITS);
4367 if (minInt != 0 || maxFrac != 1) {
4368 log_err("after setting minInt=0, maxFrac=1, get minInt %d, maxFrac %d\n", minInt, maxFrac);
4369 }
4370
4371 status = U_ZERO_ERROR;
4372 ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
4373 if ( U_FAILURE(status) ) {
4374 log_err("unum_formatDouble (maxFrac 1) 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
4375 } else if (u_strcmp(ubuf, u".0") != 0) {
4376 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4377 log_err("unum_formatDouble (maxFrac 1) 0.0 expected \".0\", got \"%s\"\n", bbuf);
4378 }
4379
4380 unum_close(unum);
4381 }
1a147d09
A
4382}
4383
3d1f044b
A
4384#if APPLE_ADDITIONS
4385#include <stdio.h>
4386#if U_PLATFORM_IS_DARWIN_BASED
4387#include <unistd.h>
4388#include <mach/mach_time.h>
4389#define GET_START() mach_absolute_time()
4390#define GET_DURATION(start, info) ((mach_absolute_time() - start) * info.numer)/info.denom
4391#elif !U_PLATFORM_HAS_WIN32_API
4392#include <unistd.h>
4393#include "putilimp.h"
4394#define GET_START() (uint64_t)uprv_getUTCtime()
4395#define GET_DURATION(start, info) ((uint64_t)uprv_getUTCtime() - start)
4396#else
4397#include "putilimp.h"
4398#define GET_START() (unsigned long long)uprv_getUTCtime()
4399#define GET_DURATION(start, info) ((unsigned long long)uprv_getUTCtime() - start)
4400#endif
4401
4402// Apple only for <rdar://problem/51672521>
4403
4404static void TestFormatDecPerf(void) {
4405 static const char* locales[] =
4406 { "en_US", "ar_EG", "ar_EG@numbers=latn", "zh_CN@numbers=traditional", NULL };
4407 static const UNumberFormatStyle styles[] =
4408 { UNUM_DECIMAL, UNUM_CURRENCY, UNUM_PATTERN_DECIMAL, UNUM_FORMAT_STYLE_COUNT };
4409 static const char* values[] =
4410 { "123.4", "234.5", "345.6", "456.7", NULL };
4411 static const UChar* pattern = u"#";
4412#if U_PLATFORM_IS_DARWIN_BASED
4413 mach_timebase_info_data_t info;
4414 mach_timebase_info(&info);
4415#endif
4416 const char** localesPtr = locales;
4417 const char* locale;
4418 while ((locale = *localesPtr++) != NULL) {
4419 const UNumberFormatStyle* stylesPtr = styles;
4420 UNumberFormatStyle style;
4421 while ((style = *stylesPtr++) < UNUM_FORMAT_STYLE_COUNT) {
4422#if !U_PLATFORM_HAS_WIN32_API
4423 uint64_t start, duration;
4424#else
4425 unsigned long long start, duration;
4426#endif
4427 UErrorCode status = U_ZERO_ERROR;
4428 const UChar* patternPtr = (style == UNUM_PATTERN_DECIMAL)? pattern: NULL;
4429 int32_t patternLen = (style == UNUM_PATTERN_DECIMAL)? u_strlen(pattern): 0;
4430 UNumberFormat *unum;
4431
4432 start = GET_START();
4433 unum = unum_open(style, patternPtr, patternLen, locale, NULL, &status);
4434 duration = GET_DURATION(start, info);
4435 log_info("== start locale %s, style %d\n", locale, (int)style);
4436 if ( U_FAILURE(status) ) {
4437 log_data_err("unum_open fails with %s\n", u_errorName(status));
4438 } else {
4439 log_info("unum_open nsec %5llu\n", duration);
4440 const char** valuesPtr = values;
4441 const char* value;
4442 while ((value = *valuesPtr++) != NULL) {
4443 UChar ubuf[kUBufMax];
4444 char bbuf[kBBufMax];
4445 int32_t ulen;
4446
4447 status = U_ZERO_ERROR;
4448 start = GET_START();
4449 ulen = unum_formatDecimal(unum, value, strlen(value), ubuf, kUBufMax, NULL, &status);
4450 duration = GET_DURATION(start, info);
4451 u_strToUTF8(bbuf, kBBufMax, NULL, ubuf, ulen, &status);
4452 if ( U_FAILURE(status) ) {
4453 log_err("unum_formatDecimal %s fails with %s\n", value, u_errorName(status));
4454 } else {
4455 log_info("unum_formatDecimal %s, nsec %5llu, result %s\n", value, duration, bbuf);
4456 }
4457 }
4458 unum_close(unum);
4459 }
4460 }
4461 }
4462}
4463
4464
4465
4466
4467
4468#endif /* APPLE_ADDITIONS */
4469
b75a7d8f 4470#endif /* #if !UCONFIG_NO_FORMATTING */