1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2007, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6 /* Modification History:
7 * Date Name Description
8 * 07/15/99 helena Ported to HPUX 10/11 CC.
9 */
10
11 #include "unicode/utypes.h"
12
13 #if !UCONFIG_NO_FORMATTING
14
15 #include "numfmtst.h"
16 #include "unicode/dcfmtsym.h"
17 #include "unicode/decimfmt.h"
18 #include "unicode/ucurr.h"
19 #include "unicode/ustring.h"
20 #include "unicode/measfmt.h"
21 #include "unicode/curramt.h"
22 #include "digitlst.h"
23 #include "textfile.h"
24 #include "tokiter.h"
25 #include "charstr.h"
26 #include "putilimp.h"
27 #include "winnmtst.h"
28 #include <float.h>
29 #include <string.h>
30
31 static const UChar EUR[] = {69,85,82,0}; // "EUR"
32
33 // *****************************************************************************
34 // class NumberFormatTest
35 // *****************************************************************************
36
37 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
38
39 #define CHECK(status,str) if (U_FAILURE(status)) { errln(UnicodeString("FAIL: ") + str); return; }
40
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)41 void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
42 {
43 // if (exec) logln((UnicodeString)"TestSuite DateFormatTest");
44 switch (index) {
45 CASE(0,TestCurrencySign);
46 CASE(1,TestCurrency);
47 CASE(2,TestParse);
48 CASE(3,TestRounding487);
49 CASE(4,TestQuotes);
50 CASE(5,TestExponential);
51 CASE(6,TestPatterns);
52
53 // Upgrade to alphaWorks - liu 5/99
54 CASE(7,TestExponent);
55 CASE(8,TestScientific);
56 CASE(9,TestPad);
57 CASE(10,TestPatterns2);
58 CASE(11,TestSecondaryGrouping);
59 CASE(12,TestSurrogateSupport);
60 CASE(13,TestAPI);
61
62 CASE(14,TestCurrencyObject);
63 CASE(15,TestCurrencyPatterns);
64 //CASE(16,TestDigitList);
65 CASE(16,TestWhiteSpaceParsing);
66 CASE(17,TestComplexCurrency);
67 CASE(18,TestRegCurrency);
68 CASE(19,TestSymbolsWithBadLocale);
69 CASE(20,TestAdoptDecimalFormatSymbols);
70
71 CASE(21,TestScientific2);
72 CASE(22,TestScientificGrouping);
73 CASE(23,TestInt64);
74
75 CASE(24,TestPerMill);
76 CASE(25,TestIllegalPatterns);
77 CASE(26,TestCases);
78
79 CASE(27,TestCurrencyNames);
80 CASE(28,TestCurrencyAmount);
81 CASE(29,TestCurrencyUnit);
82 CASE(30,TestCoverage);
83 CASE(31,TestJB3832);
84 CASE(32,TestHost);
85 CASE(33,TestHostClone);
86 CASE(34,TestCurrencyFormat);
87 CASE(35,TestRounding);
88 default: name = ""; break;
89 }
90 }
91
92 // -------------------------------------
93
94 // Test API (increase code coverage)
95 void
TestAPI(void)96 NumberFormatTest::TestAPI(void)
97 {
98 logln("Test API");
99 UErrorCode status = U_ZERO_ERROR;
100 NumberFormat *test = NumberFormat::createInstance("root", status);
101 if(U_FAILURE(status)) {
102 errln("unable to create format object");
103 }
104 if(test != NULL) {
105 test->setMinimumIntegerDigits(10);
106 test->setMaximumIntegerDigits(2);
107
108 test->setMinimumFractionDigits(10);
109 test->setMaximumFractionDigits(2);
110
111 UnicodeString result;
112 FieldPosition pos;
113 Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers
114 test->format(bla, result, pos, status);
115 if(U_SUCCESS(status)) {
116 errln("Yuck... Formatted a duck... As a number!");
117 } else {
118 status = U_ZERO_ERROR;
119 }
120
121 result.remove();
122 int64_t ll = 12;
123 test->format(ll, result);
124 if (result != "12.00"){
125 errln("format int64_t error");
126 }
127
128 delete test;
129 }
130 }
131
132 class StubNumberForamt :public NumberFormat{
133 public:
StubNumberForamt()134 StubNumberForamt(){};
format(double,UnicodeString & appendTo,FieldPosition &) const135 virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const {
136 return appendTo;
137 }
format(int32_t,UnicodeString & appendTo,FieldPosition &) const138 virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const {
139 return appendTo.append((UChar)0x0033);
140 }
format(int64_t number,UnicodeString & appendTo,FieldPosition & pos) const141 virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const {
142 return NumberFormat::format(number, appendTo, pos);
143 }
format(const Formattable &,UnicodeString & appendTo,FieldPosition &,UErrorCode &) const144 virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const {
145 return appendTo;
146 }
parse(const UnicodeString &,Formattable &,ParsePosition &) const147 virtual void parse(const UnicodeString& ,
148 Formattable& ,
149 ParsePosition& ) const {}
parse(const UnicodeString &,Formattable &,UErrorCode &) const150 virtual void parse( const UnicodeString& ,
151 Formattable& ,
152 UErrorCode& ) const {}
getDynamicClassID(void) const153 virtual UClassID getDynamicClassID(void) const {
154 static char classID = 0;
155 return (UClassID)&classID;
156 }
clone() const157 virtual Format* clone() const {return NULL;}
158 };
159
160 void
TestCoverage(void)161 NumberFormatTest::TestCoverage(void){
162 StubNumberForamt stub;
163 UnicodeString agent("agent");
164 FieldPosition pos;
165 int64_t num = 4;
166 if (stub.format(num, agent, pos) != UnicodeString("agent3")){
167 errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)");
168 };
169 }
170
171 // Test various patterns
172 void
TestPatterns(void)173 NumberFormatTest::TestPatterns(void)
174 {
175 UErrorCode status = U_ZERO_ERROR;
176 DecimalFormatSymbols sym(Locale::getUS(), status);
177 if (U_FAILURE(status)) { errln("FAIL: Could not construct DecimalFormatSymbols"); return; }
178
179 const char* pat[] = { "#.#", "#.", ".#", "#" };
180 int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
181 const char* newpat[] = { "#0.#", "#0.", "#.0", "#" };
182 const char* num[] = { "0", "0.", ".0", "0" };
183 for (int32_t i=0; i<pat_length; ++i)
184 {
185 status = U_ZERO_ERROR;
186 DecimalFormat fmt(pat[i], sym, status);
187 if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; }
188 UnicodeString newp; fmt.toPattern(newp);
189 if (!(newp == newpat[i]))
190 errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
191 "; " + newp + " seen instead");
192
193 UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s);
194 if (!(s == num[i]))
195 {
196 errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
197 "; " + s + " seen instead");
198 logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits());
199 }
200 }
201 }
202
203 /*
204 icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
205 icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
206 icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
207 */
208 /*
209 void
210 NumberFormatTest::TestDigitList(void)
211 {
212 // API coverage for DigitList
213 DigitList list1;
214 list1.append('1');
215 list1.fDecimalAt = 1;
216 DigitList list2;
217 list2.set((int32_t)1);
218 if (list1 != list2) {
219 errln("digitlist append, operator!= or set failed ");
220 }
221 if (!(list1 == list2)) {
222 errln("digitlist append, operator== or set failed ");
223 }
224 }
225 */
226
227 // -------------------------------------
228
229 // Test exponential pattern
230 void
TestExponential(void)231 NumberFormatTest::TestExponential(void)
232 {
233 UErrorCode status = U_ZERO_ERROR;
234 DecimalFormatSymbols sym(Locale::getUS(), status);
235 if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormatSymbols ct"); return; }
236 const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
237 int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
238
239 // The following #if statements allow this test to be built and run on
240 // platforms that do not have standard IEEE numerics. For example,
241 // S/390 doubles have an exponent range of -78 to +75. For the
242 // following #if statements to work, float.h must define
243 // DBL_MAX_10_EXP to be a compile-time constant.
244
245 // This section may be expanded as needed.
246
247 #if DBL_MAX_10_EXP > 300
248 double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
249 int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0]));
250 const char* valFormat[] =
251 {
252 // 0.####E0
253 "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
254 // 00.000E00
255 "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
256 // ##0.######E000
257 "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
258 // 0.###E0;[0.###E0]
259 "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]"
260 };
261 double valParse[] =
262 {
263 0.01234, 123460000, 1.23E300, -3.1416E-271,
264 0.01234, 123460000, 1.23E300, -3.1416E-271,
265 0.01234, 123456800, 1.23E300, -3.141593E-271,
266 0.01234, 123500000, 1.23E300, -3.142E-271,
267 };
268 #elif DBL_MAX_10_EXP > 70
269 double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 };
270 int32_t val_length = sizeof(val) / sizeof(val[0]);
271 char* valFormat[] =
272 {
273 // 0.####E0
274 "1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71",
275 // 00.000E00
276 "12.340E-03", "12.346E07", "12.300E69", "-31.416E-72",
277 // ##0.######E000
278 "12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072",
279 // 0.###E0;[0.###E0]
280 "1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]"
281 };
282 double valParse[] =
283 {
284 0.01234, 123460000, 1.23E70, -3.1416E-71,
285 0.01234, 123460000, 1.23E70, -3.1416E-71,
286 0.01234, 123456800, 1.23E70, -3.141593E-71,
287 0.01234, 123500000, 1.23E70, -3.142E-71,
288 };
289 #else
290 // Don't test double conversion
291 double* val = 0;
292 int32_t val_length = 0;
293 char** valFormat = 0;
294 double* valParse = 0;
295 logln("Warning: Skipping double conversion tests");
296 #endif
297
298 int32_t lval[] = { 0, -1, 1, 123456789 };
299 int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0]));
300 const char* lvalFormat[] =
301 {
302 // 0.####E0
303 "0E0", "-1E0", "1E0", "1.2346E8",
304 // 00.000E00
305 "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
306 // ##0.######E000
307 "0E000", "-1E000", "1E000", "123.4568E006",
308 // 0.###E0;[0.###E0]
309 "0E0", "[1E0]", "1E0", "1.235E8"
310 };
311 int32_t lvalParse[] =
312 {
313 0, -1, 1, 123460000,
314 0, -1, 1, 123460000,
315 0, -1, 1, 123456800,
316 0, -1, 1, 123500000,
317 };
318 int32_t ival = 0, ilval = 0;
319 for (int32_t p=0; p<pat_length; ++p)
320 {
321 DecimalFormat fmt(pat[p], sym, status);
322 if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; }
323 UnicodeString pattern;
324 logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" +
325 fmt.toPattern(pattern) + "\"");
326 int32_t v;
327 for (v=0; v<val_length; ++v)
328 {
329 UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s);
330 logln((UnicodeString)" " + val[v] + " -format-> " + s);
331 if (s != valFormat[v+ival])
332 errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]);
333
334 ParsePosition pos(0);
335 Formattable af;
336 fmt.parse(s, af, pos);
337 double a;
338 UBool useEpsilon = FALSE;
339 if (af.getType() == Formattable::kLong)
340 a = af.getLong();
341 else if (af.getType() == Formattable::kDouble) {
342 a = af.getDouble();
343 #if defined(OS390) || defined(OS400)
344 // S/390 will show a failure like this:
345 //| -3.141592652999999e-271 -format-> -3.1416E-271
346 //| -parse-> -3.1416e-271
347 //| FAIL: Expected -3.141599999999999e-271
348 // To compensate, we use an epsilon-based equality
349 // test on S/390 only. We don't want to do this in
350 // general because it's less exacting.
351 useEpsilon = TRUE;
352 #endif
353 }
354 else {
355 errln((UnicodeString)"FAIL: Non-numeric Formattable returned");
356 continue;
357 }
358 if (pos.getIndex() == s.length())
359 {
360 logln((UnicodeString)" -parse-> " + a);
361 // Use epsilon comparison as necessary
362 if ((useEpsilon &&
363 (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
364 (!useEpsilon && a != valParse[v+ival]))
365 {
366 errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]);
367 }
368 }
369 else {
370 errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
371 errln((UnicodeString)" should be (" + s.length() + " chars) -> " + valParse[v+ival]);
372 }
373 }
374 for (v=0; v<lval_length; ++v)
375 {
376 UnicodeString s;
377 (*(NumberFormat*)&fmt).format(lval[v], s);
378 logln((UnicodeString)" " + lval[v] + "L -format-> " + s);
379 if (s != lvalFormat[v+ilval])
380 errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s);
381
382 ParsePosition pos(0);
383 Formattable af;
384 fmt.parse(s, af, pos);
385 if (af.getType() == Formattable::kLong ||
386 af.getType() == Formattable::kInt64) {
387 UErrorCode status = U_ZERO_ERROR;
388 int32_t a = af.getLong(status);
389 if (pos.getIndex() == s.length())
390 {
391 logln((UnicodeString)" -parse-> " + a);
392 if (a != lvalParse[v+ilval])
393 errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]);
394 }
395 else
396 errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
397 }
398 else
399 errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s
400 + " Double: " + af.getDouble()
401 + ", Long: " + af.getLong());
402 }
403 ival += val_length;
404 ilval += lval_length;
405 }
406 }
407
408 void
TestScientific2()409 NumberFormatTest::TestScientific2() {
410 // jb 2552
411 UErrorCode status = U_ZERO_ERROR;
412 DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
413 if (U_SUCCESS(status)) {
414 double num = 12.34;
415 expect(*fmt, num, "$12.34");
416 fmt->setScientificNotation(TRUE);
417 expect(*fmt, num, "$1.23E1");
418 fmt->setScientificNotation(FALSE);
419 expect(*fmt, num, "$12.34");
420 }
421 delete fmt;
422 }
423
424 void
TestScientificGrouping()425 NumberFormatTest::TestScientificGrouping() {
426 // jb 2552
427 UErrorCode status = U_ZERO_ERROR;
428 DecimalFormat fmt("##0.00E0",status);
429 if (U_SUCCESS(status)) {
430 expect(fmt, .01234, "12.3E-3");
431 expect(fmt, .1234, "123E-3");
432 expect(fmt, 1.234, "1.23E0");
433 expect(fmt, 12.34, "12.3E0");
434 expect(fmt, 123.4, "123E0");
435 expect(fmt, 1234., "1.23E3");
436 }
437 }
438
439 /*static void setFromString(DigitList& dl, const char* str) {
440 char c;
441 UBool decimalSet = FALSE;
442 dl.clear();
443 while ((c = *str++)) {
444 if (c == '-') {
445 dl.fIsPositive = FALSE;
446 } else if (c == '+') {
447 dl.fIsPositive = TRUE;
448 } else if (c == '.') {
449 dl.fDecimalAt = dl.fCount;
450 decimalSet = TRUE;
451 } else {
452 dl.append(c);
453 }
454 }
455 if (!decimalSet) {
456 dl.fDecimalAt = dl.fCount;
457 }
458 }*/
459
460 void
TestInt64()461 NumberFormatTest::TestInt64() {
462 UErrorCode status = U_ZERO_ERROR;
463 DecimalFormat fmt("#.#E0",status);
464 fmt.setMaximumFractionDigits(20);
465 if (U_SUCCESS(status)) {
466 expect(fmt, (Formattable)(int64_t)0, "0E0");
467 expect(fmt, (Formattable)(int64_t)-1, "-1E0");
468 expect(fmt, (Formattable)(int64_t)1, "1E0");
469 expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9");
470 expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9");
471 expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18");
472 expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18");
473 }
474
475 // also test digitlist
476 /* int64_t int64max = U_INT64_MAX;
477 int64_t int64min = U_INT64_MIN;
478 const char* int64maxstr = "9223372036854775807";
479 const char* int64minstr = "-9223372036854775808";
480 UnicodeString fail("fail: ");
481
482 // test max int64 value
483 DigitList dl;
484 setFromString(dl, int64maxstr);
485 {
486 if (!dl.fitsIntoInt64(FALSE)) {
487 errln(fail + int64maxstr + " didn't fit");
488 }
489 int64_t int64Value = dl.getInt64();
490 if (int64Value != int64max) {
491 errln(fail + int64maxstr);
492 }
493 dl.set(int64Value);
494 int64Value = dl.getInt64();
495 if (int64Value != int64max) {
496 errln(fail + int64maxstr);
497 }
498 }
499 // test negative of max int64 value (1 shy of min int64 value)
500 dl.fIsPositive = FALSE;
501 {
502 if (!dl.fitsIntoInt64(FALSE)) {
503 errln(fail + "-" + int64maxstr + " didn't fit");
504 }
505 int64_t int64Value = dl.getInt64();
506 if (int64Value != -int64max) {
507 errln(fail + "-" + int64maxstr);
508 }
509 dl.set(int64Value);
510 int64Value = dl.getInt64();
511 if (int64Value != -int64max) {
512 errln(fail + "-" + int64maxstr);
513 }
514 }
515 // test min int64 value
516 setFromString(dl, int64minstr);
517 {
518 if (!dl.fitsIntoInt64(FALSE)) {
519 errln(fail + "-" + int64minstr + " didn't fit");
520 }
521 int64_t int64Value = dl.getInt64();
522 if (int64Value != int64min) {
523 errln(fail + int64minstr);
524 }
525 dl.set(int64Value);
526 int64Value = dl.getInt64();
527 if (int64Value != int64min) {
528 errln(fail + int64minstr);
529 }
530 }
531 // test negative of min int 64 value (1 more than max int64 value)
532 dl.fIsPositive = TRUE; // won't fit
533 {
534 if (dl.fitsIntoInt64(FALSE)) {
535 errln(fail + "-(" + int64minstr + ") didn't fit");
536 }
537 }*/
538 }
539
540 // -------------------------------------
541
542 // Test the handling of quotes
543 void
TestQuotes(void)544 NumberFormatTest::TestQuotes(void)
545 {
546 UErrorCode status = U_ZERO_ERROR;
547 UnicodeString *pat;
548 DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status);
549 pat = new UnicodeString("a'fo''o'b#");
550 DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status);
551 UnicodeString s;
552 ((NumberFormat*)fmt)->format((int32_t)123, s);
553 logln((UnicodeString)"Pattern \"" + *pat + "\"");
554 logln((UnicodeString)" Format 123 -> " + escape(s));
555 if (!(s=="afo'ob123"))
556 errln((UnicodeString)"FAIL: Expected afo'ob123");
557
558 s.truncate(0);
559 delete fmt;
560 delete pat;
561
562 pat = new UnicodeString("a''b#");
563 fmt = new DecimalFormat(*pat, *sym, status);
564 ((NumberFormat*)fmt)->format((int32_t)123, s);
565 logln((UnicodeString)"Pattern \"" + *pat + "\"");
566 logln((UnicodeString)" Format 123 -> " + escape(s));
567 if (!(s=="a'b123"))
568 errln((UnicodeString)"FAIL: Expected a'b123");
569 delete fmt;
570 delete pat;
571 delete sym;
572 }
573
574 /**
575 * Test the handling of the currency symbol in patterns.
576 */
577 void
TestCurrencySign(void)578 NumberFormatTest::TestCurrencySign(void)
579 {
580 UErrorCode status = U_ZERO_ERROR;
581 DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status);
582 UnicodeString pat;
583 UChar currency = 0x00A4;
584 // "\xA4#,##0.00;-\xA4#,##0.00"
585 pat.append(currency).append("#,##0.00;-").
586 append(currency).append("#,##0.00");
587 DecimalFormat *fmt = new DecimalFormat(pat, *sym, status);
588 UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s);
589 pat.truncate(0);
590 logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
591 logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
592 if (s != "$1,234.56") errln((UnicodeString)"FAIL: Expected $1,234.56");
593 s.truncate(0);
594 ((NumberFormat*)fmt)->format(- 1234.56, s);
595 logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
596 if (s != "-$1,234.56") errln((UnicodeString)"FAIL: Expected -$1,234.56");
597 delete fmt;
598 pat.truncate(0);
599 // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
600 pat.append(currency).append(currency).
601 append(" #,##0.00;").
602 append(currency).append(currency).
603 append(" -#,##0.00");
604 fmt = new DecimalFormat(pat, *sym, status);
605 s.truncate(0);
606 ((NumberFormat*)fmt)->format(1234.56, s);
607 logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
608 logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
609 if (s != "USD 1,234.56") errln((UnicodeString)"FAIL: Expected USD 1,234.56");
610 s.truncate(0);
611 ((NumberFormat*)fmt)->format(-1234.56, s);
612 logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
613 if (s != "USD -1,234.56") errln((UnicodeString)"FAIL: Expected USD -1,234.56");
614 delete fmt;
615 delete sym;
616 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
617 }
618
619 // -------------------------------------
620
toHexString(int32_t i)621 static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
622
623 UnicodeString&
escape(UnicodeString & s)624 NumberFormatTest::escape(UnicodeString& s)
625 {
626 UnicodeString buf;
627 for (int32_t i=0; i<s.length(); ++i)
628 {
629 UChar c = s[(int32_t)i];
630 if (c <= (UChar)0x7F) buf += c;
631 else {
632 buf += (UChar)0x5c; buf += (UChar)0x55;
633 buf += toHexString((c & 0xF000) >> 12);
634 buf += toHexString((c & 0x0F00) >> 8);
635 buf += toHexString((c & 0x00F0) >> 4);
636 buf += toHexString(c & 0x000F);
637 }
638 }
639 return (s = buf);
640 }
641
642
643 // -------------------------------------
644 static const char* testCases[][2]= {
645 /* locale ID */ /* expected */
646 {"ca_ES_PREEURO", "1.150 \\u20A7" },
647 {"de_LU_PREEURO", "1,150 F" },
648 {"el_GR_PREEURO", "1.150,50\\u0394\\u03C1\\u03C7" },
649 {"en_BE_PREEURO", "1.150,50 BF" },
650 {"es_ES_PREEURO", "1.150 \\u20A7" },
651 {"eu_ES_PREEURO", "1.150 \\u20A7" },
652 {"gl_ES_PREEURO", "1.150 \\u20A7" },
653 {"it_IT_PREEURO", "\\u20A4 1.150" },
654 {"pt_PT_PREEURO", "1,150$50 Esc."},
655 {"en_US@currency=JPY", "\\u00A51,150"}
656 };
657 /**
658 * Test localized currency patterns.
659 */
660 void
TestCurrency(void)661 NumberFormatTest::TestCurrency(void)
662 {
663 UErrorCode status = U_ZERO_ERROR;
664 NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status);
665 if (U_FAILURE(status)) {
666 dataerrln("Error calling NumberFormat::createCurrencyInstance()");
667 return;
668 }
669
670 UnicodeString s; currencyFmt->format(1.50, s);
671 logln((UnicodeString)"Un pauvre ici a..........." + s);
672 if (!(s=="1,50 $"))
673 errln((UnicodeString)"FAIL: Expected 1,50 $");
674 delete currencyFmt;
675 s.truncate(0);
676 char loc[256]={0};
677 int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
678 currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status);
679 currencyFmt->format(1.50, s);
680 logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
681 if (!(s=="1,50 DM"))
682 errln((UnicodeString)"FAIL: Expected 1,50 DM");
683 delete currencyFmt;
684 s.truncate(0);
685 len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
686 currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
687 currencyFmt->format(1.50, s);
688 logln((UnicodeString)"Un pauvre en France a....." + s);
689 if (!(s=="1,50 F"))
690 errln((UnicodeString)"FAIL: Expected 1,50 F");
691 delete currencyFmt;
692 if (U_FAILURE(status))
693 errln((UnicodeString)"FAIL: Status " + (int32_t)status);
694
695 for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){
696 status = U_ZERO_ERROR;
697 const char *localeID = testCases[i][0];
698 UnicodeString expected(testCases[i][1]);
699 expected = expected.unescape();
700 s.truncate(0);
701 char loc[256]={0};
702 uloc_canonicalize(localeID, loc, 256, &status);
703 currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
704 if(U_FAILURE(status)){
705 errln("Could not create currency formatter for locale %s",localeID);
706 continue;
707 }
708 currencyFmt->format(1150.50, s);
709 if(s!=expected){
710 errln(UnicodeString("FAIL: Expected: ")+expected
711 + UnicodeString(" Got: ") + s
712 + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
713 }
714 if (U_FAILURE(status)){
715 errln((UnicodeString)"FAIL: Status " + (int32_t)status);
716 }
717 delete currencyFmt;
718 }
719 }
720
721 // -------------------------------------
722
723 /**
724 * Test the Currency object handling, new as of ICU 2.2.
725 */
TestCurrencyObject()726 void NumberFormatTest::TestCurrencyObject() {
727 UErrorCode ec = U_ZERO_ERROR;
728 NumberFormat* fmt =
729 NumberFormat::createCurrencyInstance(Locale::getUS(), ec);
730
731 if (U_FAILURE(ec)) {
732 errln("FAIL: getCurrencyInstance(US)");
733 delete fmt;
734 return;
735 }
736
737 Locale null("", "", "");
738
739 expectCurrency(*fmt, null, 1234.56, "$1,234.56");
740
741 expectCurrency(*fmt, Locale::getFrance(),
742 1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro
743
744 expectCurrency(*fmt, Locale::getJapan(),
745 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
746
747 expectCurrency(*fmt, Locale("fr", "CH", ""),
748 1234.56, "SwF1,234.55"); // 0.05 rounding
749
750 expectCurrency(*fmt, Locale::getUS(),
751 1234.56, "$1,234.56");
752
753 delete fmt;
754 fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec);
755
756 if (U_FAILURE(ec)) {
757 errln("FAIL: getCurrencyInstance(FRANCE)");
758 delete fmt;
759 return;
760 }
761
762 expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC"));
763
764 expectCurrency(*fmt, Locale::getJapan(),
765 1234.56, CharsToUnicodeString("1 235 \\u00A5JP")); // Yen
766
767 expectCurrency(*fmt, Locale("fr", "CH", ""),
768 1234.56, "1 234,55 sFr."); // 0.05 rounding
769
770 expectCurrency(*fmt, Locale::getUS(),
771 1234.56, "1 234,56 $US");
772
773 expectCurrency(*fmt, Locale::getFrance(),
774 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro
775
776 delete fmt;
777 }
778
779 // -------------------------------------
780
781 /**
782 * Do rudimentary testing of parsing.
783 */
784 void
TestParse(void)785 NumberFormatTest::TestParse(void)
786 {
787 UErrorCode status = U_ZERO_ERROR;
788 UnicodeString arg("0");
789 DecimalFormat* format = new DecimalFormat("00", status);
790 //try {
791 Formattable n; format->parse(arg, n, status);
792 logln((UnicodeString)"parse(" + arg + ") = " + n.getLong());
793 if (n.getType() != Formattable::kLong ||
794 n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
795 delete format;
796 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
797 //}
798 //catch(Exception e) {
799 // errln((UnicodeString)"Exception caught: " + e);
800 //}
801 }
802
803 // -------------------------------------
804
805 /**
806 * Test proper rounding by the format method.
807 */
808 void
TestRounding487(void)809 NumberFormatTest::TestRounding487(void)
810 {
811 UErrorCode status = U_ZERO_ERROR;
812 NumberFormat *nf = NumberFormat::createInstance(status);
813 if (U_FAILURE(status)) {
814 dataerrln("Error calling NumberFormat::createInstance()");
815 return;
816 }
817
818 roundingTest(*nf, 0.00159999, 4, "0.0016");
819 roundingTest(*nf, 0.00995, 4, "0.01");
820
821 roundingTest(*nf, 12.3995, 3, "12.4");
822
823 roundingTest(*nf, 12.4999, 0, "12");
824 roundingTest(*nf, - 19.5, 0, "-20");
825 delete nf;
826 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
827 }
828
829 /**
830 * Test the functioning of the secondary grouping value.
831 */
TestSecondaryGrouping(void)832 void NumberFormatTest::TestSecondaryGrouping(void) {
833 UErrorCode status = U_ZERO_ERROR;
834 DecimalFormatSymbols US(Locale::getUS(), status);
835 CHECK(status, "DecimalFormatSymbols ct");
836
837 DecimalFormat f("#,##,###", US, status);
838 CHECK(status, "DecimalFormat ct");
839
840 expect2(f, (int32_t)123456789L, "12,34,56,789");
841 expectPat(f, "#,##,###");
842 f.applyPattern("#,###", status);
843 CHECK(status, "applyPattern");
844
845 f.setSecondaryGroupingSize(4);
846 expect2(f, (int32_t)123456789L, "12,3456,789");
847 expectPat(f, "#,####,###");
848 NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status);
849 CHECK(status, "createInstance(hi_IN)");
850
851 UnicodeString out;
852 int32_t l = (int32_t)1876543210L;
853 g->format(l, out);
854 delete g;
855 // expect "1,87,65,43,210", but with Hindi digits
856 // 01234567890123
857 UBool ok = TRUE;
858 if (out.length() != 14) {
859 ok = FALSE;
860 } else {
861 for (int32_t i=0; i<out.length(); ++i) {
862 UBool expectGroup = FALSE;
863 switch (i) {
864 case 1:
865 case 4:
866 case 7:
867 case 10:
868 expectGroup = TRUE;
869 break;
870 }
871 // Later -- fix this to get the actual grouping
872 // character from the resource bundle.
873 UBool isGroup = (out.charAt(i) == 0x002C);
874 if (isGroup != expectGroup) {
875 ok = FALSE;
876 break;
877 }
878 }
879 }
880 if (!ok) {
881 errln((UnicodeString)"FAIL Expected " + l +
882 " x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" +
883 escape(out) + "\"");
884 } else {
885 logln((UnicodeString)"Ok " + l +
886 " x hi_IN -> \"" +
887 escape(out) + "\"");
888 }
889 }
890
TestWhiteSpaceParsing(void)891 void NumberFormatTest::TestWhiteSpaceParsing(void) {
892 UErrorCode ec = U_ZERO_ERROR;
893 DecimalFormatSymbols US(Locale::getUS(), ec);
894 DecimalFormat fmt("a b#0c ", US, ec);
895 if (U_FAILURE(ec)) {
896 errln("FAIL: Constructor");
897 return;
898 }
899 int32_t n = 1234;
900 expect(fmt, "a b1234c ", n);
901 expect(fmt, "a b1234c ", n);
902 }
903
904 /**
905 * Test currencies whose display name is a ChoiceFormat.
906 */
TestComplexCurrency()907 void NumberFormatTest::TestComplexCurrency() {
908 UErrorCode ec = U_ZERO_ERROR;
909 Locale loc("en", "IN", "");
910 NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
911 if (U_SUCCESS(ec)) {
912 expect2(*fmt, 1.0, "Re. 1.00");
913 // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
914 expect(*fmt, 1.00390625, "Re. 1.00"); // tricky
915 expect2(*fmt, 12345678.0, "Rs. 1,23,45,678.00");
916 expect2(*fmt, 0.5, "Rs. 0.50");
917 expect2(*fmt, -1.0, "-Re. 1.00");
918 expect2(*fmt, -10.0, "-Rs. 10.00");
919 } else {
920 errln("FAIL: getCurrencyInstance(en_IN)");
921 }
922 delete fmt;
923 }
924
925 // -------------------------------------
926
927 void
roundingTest(NumberFormat & nf,double x,int32_t maxFractionDigits,const char * expected)928 NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected)
929 {
930 nf.setMaximumFractionDigits(maxFractionDigits);
931 UnicodeString out; nf.format(x, out);
932 logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out);
933 if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected);
934 }
935
936 /**
937 * Upgrade to alphaWorks
938 */
TestExponent(void)939 void NumberFormatTest::TestExponent(void) {
940 UErrorCode status = U_ZERO_ERROR;
941 DecimalFormatSymbols US(Locale::getUS(), status);
942 CHECK(status, "DecimalFormatSymbols constructor");
943 DecimalFormat fmt1(UnicodeString("0.###E0"), US, status);
944 CHECK(status, "DecimalFormat(0.###E0)");
945 DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status);
946 CHECK(status, "DecimalFormat(0.###E+0)");
947 int32_t n = 1234;
948 expect2(fmt1, n, "1.234E3");
949 expect2(fmt2, n, "1.234E+3");
950 expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
951 }
952
953 /**
954 * Upgrade to alphaWorks
955 */
TestScientific(void)956 void NumberFormatTest::TestScientific(void) {
957 UErrorCode status = U_ZERO_ERROR;
958 DecimalFormatSymbols US(Locale::getUS(), status);
959 CHECK(status, "DecimalFormatSymbols constructor");
960
961 // Test pattern round-trip
962 const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000",
963 "0.###E0;[0.###E0]" };
964 int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0]));
965 int32_t DIGITS[] = {
966 // min int, max int, min frac, max frac
967 0, 1, 0, 0, // "#E0"
968 1, 1, 0, 4, // "0.####E0"
969 2, 2, 3, 3, // "00.000E00"
970 1, 3, 0, 4, // "##0.####E000"
971 1, 1, 0, 3, // "0.###E0;[0.###E0]"
972 };
973 for (int32_t i=0; i<PAT_length; ++i) {
974 UnicodeString pat(PAT[i]);
975 DecimalFormat df(pat, US, status);
976 CHECK(status, "DecimalFormat constructor");
977 UnicodeString pat2;
978 df.toPattern(pat2);
979 if (pat == pat2) {
980 logln(UnicodeString("Ok Pattern rt \"") +
981 pat + "\" -> \"" +
982 pat2 + "\"");
983 } else {
984 errln(UnicodeString("FAIL Pattern rt \"") +
985 pat + "\" -> \"" +
986 pat2 + "\"");
987 }
988 // Make sure digit counts match what we expect
989 if (df.getMinimumIntegerDigits() != DIGITS[4*i] ||
990 df.getMaximumIntegerDigits() != DIGITS[4*i+1] ||
991 df.getMinimumFractionDigits() != DIGITS[4*i+2] ||
992 df.getMaximumFractionDigits() != DIGITS[4*i+3]) {
993 errln(UnicodeString("FAIL \"" + pat +
994 "\" min/max int; min/max frac = ") +
995 df.getMinimumIntegerDigits() + "/" +
996 df.getMaximumIntegerDigits() + ";" +
997 df.getMinimumFractionDigits() + "/" +
998 df.getMaximumFractionDigits() + ", expect " +
999 DIGITS[4*i] + "/" +
1000 DIGITS[4*i+1] + ";" +
1001 DIGITS[4*i+2] + "/" +
1002 DIGITS[4*i+3]);
1003 }
1004 }
1005
1006
1007 // Test the constructor for default locale. We have to
1008 // manually set the default locale, as there is no
1009 // guarantee that the default locale has the same
1010 // scientific format.
1011 Locale def = Locale::getDefault();
1012 Locale::setDefault(Locale::getUS(), status);
1013 expect2(NumberFormat::createScientificInstance(status),
1014 12345.678901,
1015 "1.2345678901E4", status);
1016 Locale::setDefault(def, status);
1017
1018 expect2(new DecimalFormat("#E0", US, status),
1019 12345.0,
1020 "1.2345E4", status);
1021 expect(new DecimalFormat("0E0", US, status),
1022 12345.0,
1023 "1E4", status);
1024 expect2(NumberFormat::createScientificInstance(Locale::getUS(), status),
1025 12345.678901,
1026 "1.2345678901E4", status);
1027 expect(new DecimalFormat("##0.###E0", US, status),
1028 12345.0,
1029 "12.34E3", status);
1030 expect(new DecimalFormat("##0.###E0", US, status),
1031 12345.00001,
1032 "12.35E3", status);
1033 expect2(new DecimalFormat("##0.####E0", US, status),
1034 (int32_t) 12345,
1035 "12.345E3", status);
1036 expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status),
1037 12345.678901,
1038 "1,2345678901E4", status);
1039 expect(new DecimalFormat("##0.####E0", US, status),
1040 789.12345e-9,
1041 "789.12E-9", status);
1042 expect2(new DecimalFormat("##0.####E0", US, status),
1043 780.e-9,
1044 "780E-9", status);
1045 expect(new DecimalFormat(".###E0", US, status),
1046 45678.0,
1047 ".457E5", status);
1048 expect2(new DecimalFormat(".###E0", US, status),
1049 (int32_t) 0,
1050 ".0E0", status);
1051 /*
1052 expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
1053 new DecimalFormat("##E0", US),
1054 new DecimalFormat("####E0", US),
1055 new DecimalFormat("0E0", US),
1056 new DecimalFormat("00E0", US),
1057 new DecimalFormat("000E0", US),
1058 },
1059 new Long(45678000),
1060 new String[] { "4.5678E7",
1061 "45.678E6",
1062 "4567.8E4",
1063 "5E7",
1064 "46E6",
1065 "457E5",
1066 }
1067 );
1068 !
1069 ! Unroll this test into individual tests below...
1070 !
1071 */
1072 expect2(new DecimalFormat("#E0", US, status),
1073 (int32_t) 45678000, "4.5678E7", status);
1074 expect2(new DecimalFormat("##E0", US, status),
1075 (int32_t) 45678000, "45.678E6", status);
1076 expect2(new DecimalFormat("####E0", US, status),
1077 (int32_t) 45678000, "4567.8E4", status);
1078 expect(new DecimalFormat("0E0", US, status),
1079 (int32_t) 45678000, "5E7", status);
1080 expect(new DecimalFormat("00E0", US, status),
1081 (int32_t) 45678000, "46E6", status);
1082 expect(new DecimalFormat("000E0", US, status),
1083 (int32_t) 45678000, "457E5", status);
1084 /*
1085 expect(new DecimalFormat("###E0", US, status),
1086 new Object[] { new Double(0.0000123), "12.3E-6",
1087 new Double(0.000123), "123E-6",
1088 new Double(0.00123), "1.23E-3",
1089 new Double(0.0123), "12.3E-3",
1090 new Double(0.123), "123E-3",
1091 new Double(1.23), "1.23E0",
1092 new Double(12.3), "12.3E0",
1093 new Double(123), "123E0",
1094 new Double(1230), "1.23E3",
1095 });
1096 !
1097 ! Unroll this test into individual tests below...
1098 !
1099 */
1100 expect2(new DecimalFormat("###E0", US, status),
1101 0.0000123, "12.3E-6", status);
1102 expect2(new DecimalFormat("###E0", US, status),
1103 0.000123, "123E-6", status);
1104 expect2(new DecimalFormat("###E0", US, status),
1105 0.00123, "1.23E-3", status);
1106 expect2(new DecimalFormat("###E0", US, status),
1107 0.0123, "12.3E-3", status);
1108 expect2(new DecimalFormat("###E0", US, status),
1109 0.123, "123E-3", status);
1110 expect2(new DecimalFormat("###E0", US, status),
1111 1.23, "1.23E0", status);
1112 expect2(new DecimalFormat("###E0", US, status),
1113 12.3, "12.3E0", status);
1114 expect2(new DecimalFormat("###E0", US, status),
1115 123.0, "123E0", status);
1116 expect2(new DecimalFormat("###E0", US, status),
1117 1230.0, "1.23E3", status);
1118 /*
1119 expect(new DecimalFormat("0.#E+00", US, status),
1120 new Object[] { new Double(0.00012), "1.2E-04",
1121 new Long(12000), "1.2E+04",
1122 });
1123 !
1124 ! Unroll this test into individual tests below...
1125 !
1126 */
1127 expect2(new DecimalFormat("0.#E+00", US, status),
1128 0.00012, "1.2E-04", status);
1129 expect2(new DecimalFormat("0.#E+00", US, status),
1130 (int32_t) 12000, "1.2E+04", status);
1131 }
1132
1133 /**
1134 * Upgrade to alphaWorks
1135 */
TestPad(void)1136 void NumberFormatTest::TestPad(void) {
1137 UErrorCode status = U_ZERO_ERROR;
1138 DecimalFormatSymbols US(Locale::getUS(), status);
1139 CHECK(status, "DecimalFormatSymbols constructor");
1140
1141 expect2(new DecimalFormat("*^##.##", US, status),
1142 int32_t(0), "^^^^0", status);
1143 expect2(new DecimalFormat("*^##.##", US, status),
1144 -1.3, "^-1.3", status);
1145 expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
1146 int32_t(0), "0.0E0______ g-m/s^2", status);
1147 expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
1148 1.0/3, "333.333E-3_ g-m/s^2", status);
1149 expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
1150 int32_t(0), "0.0______ g-m/s^2", status);
1151 expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
1152 1.0/3, "0.33333__ g-m/s^2", status);
1153
1154 // Test padding before a sign
1155 const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
1156 expect2(new DecimalFormat(formatStr, US, status),
1157 int32_t(-10), "xxxxxxxxxx(10.0)", status);
1158 expect2(new DecimalFormat(formatStr, US, status),
1159 int32_t(-1000),"xxxxxxx(1,000.0)", status);
1160 expect2(new DecimalFormat(formatStr, US, status),
1161 int32_t(-1000000),"xxx(1,000,000.0)", status);
1162 expect2(new DecimalFormat(formatStr, US, status),
1163 -100.37, "xxxxxxxx(100.37)", status);
1164 expect2(new DecimalFormat(formatStr, US, status),
1165 -10456.37, "xxxxx(10,456.37)", status);
1166 expect2(new DecimalFormat(formatStr, US, status),
1167 -1120456.37, "xx(1,120,456.37)", status);
1168 expect2(new DecimalFormat(formatStr, US, status),
1169 -112045600.37, "(112,045,600.37)", status);
1170 expect2(new DecimalFormat(formatStr, US, status),
1171 -1252045600.37,"(1,252,045,600.37)", status);
1172
1173 expect2(new DecimalFormat(formatStr, US, status),
1174 int32_t(10), "xxxxxxxxxxxx10.0", status);
1175 expect2(new DecimalFormat(formatStr, US, status),
1176 int32_t(1000),"xxxxxxxxx1,000.0", status);
1177 expect2(new DecimalFormat(formatStr, US, status),
1178 int32_t(1000000),"xxxxx1,000,000.0", status);
1179 expect2(new DecimalFormat(formatStr, US, status),
1180 100.37, "xxxxxxxxxx100.37", status);
1181 expect2(new DecimalFormat(formatStr, US, status),
1182 10456.37, "xxxxxxx10,456.37", status);
1183 expect2(new DecimalFormat(formatStr, US, status),
1184 1120456.37, "xxxx1,120,456.37", status);
1185 expect2(new DecimalFormat(formatStr, US, status),
1186 112045600.37, "xx112,045,600.37", status);
1187 expect2(new DecimalFormat(formatStr, US, status),
1188 10252045600.37,"10,252,045,600.37", status);
1189
1190
1191 // Test padding between a sign and a number
1192 const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
1193 expect2(new DecimalFormat(formatStr2, US, status),
1194 int32_t(-10), "(10.0xxxxxxxxxx)", status);
1195 expect2(new DecimalFormat(formatStr2, US, status),
1196 int32_t(-1000),"(1,000.0xxxxxxx)", status);
1197 expect2(new DecimalFormat(formatStr2, US, status),
1198 int32_t(-1000000),"(1,000,000.0xxx)", status);
1199 expect2(new DecimalFormat(formatStr2, US, status),
1200 -100.37, "(100.37xxxxxxxx)", status);
1201 expect2(new DecimalFormat(formatStr2, US, status),
1202 -10456.37, "(10,456.37xxxxx)", status);
1203 expect2(new DecimalFormat(formatStr2, US, status),
1204 -1120456.37, "(1,120,456.37xx)", status);
1205 expect2(new DecimalFormat(formatStr2, US, status),
1206 -112045600.37, "(112,045,600.37)", status);
1207 expect2(new DecimalFormat(formatStr2, US, status),
1208 -1252045600.37,"(1,252,045,600.37)", status);
1209
1210 expect2(new DecimalFormat(formatStr2, US, status),
1211 int32_t(10), "10.0xxxxxxxxxxxx", status);
1212 expect2(new DecimalFormat(formatStr2, US, status),
1213 int32_t(1000),"1,000.0xxxxxxxxx", status);
1214 expect2(new DecimalFormat(formatStr2, US, status),
1215 int32_t(1000000),"1,000,000.0xxxxx", status);
1216 expect2(new DecimalFormat(formatStr2, US, status),
1217 100.37, "100.37xxxxxxxxxx", status);
1218 expect2(new DecimalFormat(formatStr2, US, status),
1219 10456.37, "10,456.37xxxxxxx", status);
1220 expect2(new DecimalFormat(formatStr2, US, status),
1221 1120456.37, "1,120,456.37xxxx", status);
1222 expect2(new DecimalFormat(formatStr2, US, status),
1223 112045600.37, "112,045,600.37xx", status);
1224 expect2(new DecimalFormat(formatStr2, US, status),
1225 10252045600.37,"10,252,045,600.37", status);
1226
1227 //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
1228 DecimalFormat fmt("#", US, status);
1229 CHECK(status, "DecimalFormat constructor");
1230 UnicodeString padString("P");
1231 fmt.setPadCharacter(padString);
1232 expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString);
1233 fmt.setPadCharacter((UnicodeString)"^");
1234 expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^");
1235 //commented untill implementation is complete
1236 /* fmt.setPadCharacter((UnicodeString)"^^^");
1237 expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^");
1238 padString.remove();
1239 padString.append((UChar)0x0061);
1240 padString.append((UChar)0x0302);
1241 fmt.setPadCharacter(padString);
1242 UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
1243 UnicodeString pattern(patternChars);
1244 expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString);
1245 */
1246
1247 }
1248
1249 /**
1250 * Upgrade to alphaWorks
1251 */
TestPatterns2(void)1252 void NumberFormatTest::TestPatterns2(void) {
1253 UErrorCode status = U_ZERO_ERROR;
1254 DecimalFormatSymbols US(Locale::getUS(), status);
1255 CHECK(status, "DecimalFormatSymbols constructor");
1256
1257 DecimalFormat fmt("#", US, status);
1258 CHECK(status, "DecimalFormat constructor");
1259
1260 UChar hat = 0x005E; /*^*/
1261
1262 expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
1263 expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat);
1264 expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat);
1265 expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat);
1266 expectPad(fmt, "$*^$#", ILLEGAL);
1267 expectPad(fmt, "#$*^$", ILLEGAL);
1268 expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix,
1269 12, (UChar)0x0078 /*x*/);
1270 expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix,
1271 3, (UChar)0x0078 /*x*/);
1272 expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix,
1273 10, (UChar)0x0061 /*a*/);
1274
1275 fmt.applyPattern("AA#,##0.00ZZ", status);
1276 CHECK(status, "applyPattern");
1277 fmt.setPadCharacter(hat);
1278
1279 fmt.setFormatWidth(10);
1280
1281 fmt.setPadPosition(DecimalFormat::kPadBeforePrefix);
1282 expectPat(fmt, "*^AA#,##0.00ZZ");
1283
1284 fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix);
1285 expectPat(fmt, "AA#,##0.00*^ZZ");
1286
1287 fmt.setPadPosition(DecimalFormat::kPadAfterSuffix);
1288 expectPat(fmt, "AA#,##0.00ZZ*^");
1289
1290 // 12 3456789012
1291 UnicodeString exp("AA*^#,##0.00ZZ", "");
1292 fmt.setFormatWidth(12);
1293 fmt.setPadPosition(DecimalFormat::kPadAfterPrefix);
1294 expectPat(fmt, exp);
1295
1296 fmt.setFormatWidth(13);
1297 // 12 34567890123
1298 expectPat(fmt, "AA*^##,##0.00ZZ");
1299
1300 fmt.setFormatWidth(14);
1301 // 12 345678901234
1302 expectPat(fmt, "AA*^###,##0.00ZZ");
1303
1304 fmt.setFormatWidth(15);
1305 // 12 3456789012345
1306 expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
1307
1308 fmt.setFormatWidth(16);
1309 // 12 34567890123456
1310 expectPat(fmt, "AA*^#,###,##0.00ZZ");
1311 }
1312
TestSurrogateSupport(void)1313 void NumberFormatTest::TestSurrogateSupport(void) {
1314 UErrorCode status = U_ZERO_ERROR;
1315 DecimalFormatSymbols custom(Locale::getUS(), status);
1316 CHECK(status, "DecimalFormatSymbols constructor");
1317
1318 custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal");
1319 custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus");
1320 custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus ");
1321 custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent");
1322
1323 UnicodeString patternStr("*\\U00010000##.##", "");
1324 patternStr = patternStr.unescape();
1325 UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", "");
1326 expStr = expStr.unescape();
1327 expect2(new DecimalFormat(patternStr, custom, status),
1328 int32_t(0), expStr, status);
1329
1330 status = U_ZERO_ERROR;
1331 expect2(new DecimalFormat("*^##.##", custom, status),
1332 int32_t(0), "^^^^0", status);
1333 status = U_ZERO_ERROR;
1334 expect2(new DecimalFormat("##.##", custom, status),
1335 -1.3, " minus 1decimal3", status);
1336 status = U_ZERO_ERROR;
1337 expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
1338 int32_t(0), "0decimal0exponent0 g-m/s^2", status);
1339 status = U_ZERO_ERROR;
1340 expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
1341 1.0/3, "333decimal333exponent minus 3 g-m/s^2", status);
1342 status = U_ZERO_ERROR;
1343 expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
1344 int32_t(0), "0decimal0 g-m/s^2", status);
1345 status = U_ZERO_ERROR;
1346 expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
1347 1.0/3, "0decimal33333 g-m/s^2", status);
1348
1349 UnicodeString zero((UChar32)0x10000);
1350 custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
1351 expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", "");
1352 expStr = expStr.unescape();
1353 status = U_ZERO_ERROR;
1354 expect2(new DecimalFormat("##0.000", custom, status),
1355 1.25, expStr, status);
1356
1357 custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
1358 custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
1359 custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
1360 patternStr = "0.00 \\u00A4' in your bank account'";
1361 patternStr = patternStr.unescape();
1362 expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", "");
1363 status = U_ZERO_ERROR;
1364 expect2(new DecimalFormat(patternStr, custom, status),
1365 int32_t(-20), expStr, status);
1366
1367 custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent");
1368 patternStr = "'You''ve lost ' -0.00 %' of your money today'";
1369 patternStr = patternStr.unescape();
1370 expStr = UnicodeString(" minus You've lost minus 2000decimal00 percent of your money today", "");
1371 status = U_ZERO_ERROR;
1372 expect2(new DecimalFormat(patternStr, custom, status),
1373 int32_t(-20), expStr, status);
1374 }
1375
TestCurrencyPatterns(void)1376 void NumberFormatTest::TestCurrencyPatterns(void) {
1377 int32_t i, locCount;
1378 const Locale* locs = NumberFormat::getAvailableLocales(locCount);
1379 for (i=0; i<locCount; ++i) {
1380 UErrorCode ec = U_ZERO_ERROR;
1381 NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec);
1382 if (U_FAILURE(ec)) {
1383 errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec));
1384 } else {
1385 // Make sure currency formats do not have a variable number
1386 // of fraction digits
1387 int32_t min = nf->getMinimumFractionDigits();
1388 int32_t max = nf->getMaximumFractionDigits();
1389 if (min != max) {
1390 UnicodeString a, b;
1391 nf->format(1.0, a);
1392 nf->format(1.125, b);
1393 errln((UnicodeString)"FAIL: " + locs[i].getName() +
1394 " min fraction digits != max fraction digits; "
1395 "x 1.0 => " + escape(a) +
1396 "; x 1.125 => " + escape(b));
1397 }
1398
1399 // Make sure EURO currency formats have exactly 2 fraction digits
1400 if (nf->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
1401 DecimalFormat* df = (DecimalFormat*) nf;
1402 if (u_strcmp(EUR, df->getCurrency()) == 0) {
1403 if (min != 2 || max != 2) {
1404 UnicodeString a;
1405 nf->format(1.0, a);
1406 errln((UnicodeString)"FAIL: " + locs[i].getName() +
1407 " is a EURO format but it does not have 2 fraction digits; "
1408 "x 1.0 => " +
1409 escape(a));
1410 }
1411 }
1412 }
1413 }
1414 delete nf;
1415 }
1416 }
1417
TestRegCurrency(void)1418 void NumberFormatTest::TestRegCurrency(void) {
1419 #if !UCONFIG_NO_SERVICE
1420 UErrorCode status = U_ZERO_ERROR;
1421 UChar USD[4];
1422 ucurr_forLocale("en_US", USD, 4, &status);
1423 UChar YEN[4];
1424 ucurr_forLocale("ja_JP", YEN, 4, &status);
1425 UChar TMP[4];
1426 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
1427 if(U_FAILURE(status)) {
1428 errln("Unable to get currency for locale, error %s", u_errorName(status));
1429 return;
1430 }
1431
1432 UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status);
1433 UCurrRegistryKey enUSEUROkey = ucurr_register(QQQ, "en_US_EURO", &status);
1434
1435 ucurr_forLocale("en_US", TMP, 4, &status);
1436 if (u_strcmp(YEN, TMP) != 0) {
1437 errln("FAIL: didn't return YEN registered for en_US");
1438 }
1439
1440 ucurr_forLocale("en_US_EURO", TMP, 4, &status);
1441 if (u_strcmp(QQQ, TMP) != 0) {
1442 errln("FAIL: didn't return QQQ for en_US_EURO");
1443 }
1444
1445 int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status);
1446 if (fallbackLen) {
1447 errln("FAIL: tried to fallback en_XX_BAR");
1448 }
1449 status = U_ZERO_ERROR; // reset
1450
1451 if (!ucurr_unregister(enkey, &status)) {
1452 errln("FAIL: couldn't unregister enkey");
1453 }
1454
1455 ucurr_forLocale("en_US", TMP, 4, &status);
1456 if (u_strcmp(USD, TMP) != 0) {
1457 errln("FAIL: didn't return USD for en_US after unregister of en_US");
1458 }
1459 status = U_ZERO_ERROR; // reset
1460
1461 ucurr_forLocale("en_US_EURO", TMP, 4, &status);
1462 if (u_strcmp(QQQ, TMP) != 0) {
1463 errln("FAIL: didn't return QQQ for en_US_EURO after unregister of en_US");
1464 }
1465
1466 ucurr_forLocale("en_US_BLAH", TMP, 4, &status);
1467 if (u_strcmp(USD, TMP) != 0) {
1468 errln("FAIL: could not find USD for en_US_BLAH after unregister of en");
1469 }
1470 status = U_ZERO_ERROR; // reset
1471
1472 if (!ucurr_unregister(enUSEUROkey, &status)) {
1473 errln("FAIL: couldn't unregister enUSEUROkey");
1474 }
1475
1476 ucurr_forLocale("en_US_EURO", TMP, 4, &status);
1477 if (u_strcmp(EUR, TMP) != 0) {
1478 errln("FAIL: didn't return EUR for en_US_EURO after unregister of en_US_EURO");
1479 }
1480 status = U_ZERO_ERROR; // reset
1481 #endif
1482 }
1483
TestCurrencyNames(void)1484 void NumberFormatTest::TestCurrencyNames(void) {
1485 // Do a basic check of getName()
1486 // USD { "US$", "US Dollar" } // 04/04/1792-
1487 UErrorCode ec = U_ZERO_ERROR;
1488 static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/
1489 static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/
1490 static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/
1491 static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/
1492 UBool isChoiceFormat;
1493 int32_t len;
1494 // Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK
1495 // THE LOCALE DATA before diving into the code.
1496 assertEquals("USD.getName(SYMBOL_NAME)",
1497 UnicodeString("$"),
1498 UnicodeString(ucurr_getName(USD, "en",
1499 UCURR_SYMBOL_NAME,
1500 &isChoiceFormat, &len, &ec)));
1501 assertEquals("USD.getName(LONG_NAME)",
1502 UnicodeString("US Dollar"),
1503 UnicodeString(ucurr_getName(USD, "en",
1504 UCURR_LONG_NAME,
1505 &isChoiceFormat, &len, &ec)));
1506 assertEquals("CAD.getName(SYMBOL_NAME)",
1507 UnicodeString("Can$"),
1508 UnicodeString(ucurr_getName(CAD, "en",
1509 UCURR_SYMBOL_NAME,
1510 &isChoiceFormat, &len, &ec)));
1511 assertEquals("CAD.getName(SYMBOL_NAME)",
1512 UnicodeString("$"),
1513 UnicodeString(ucurr_getName(CAD, "en_CA",
1514 UCURR_SYMBOL_NAME,
1515 &isChoiceFormat, &len, &ec)));
1516 assertEquals("USD.getName(SYMBOL_NAME)",
1517 UnicodeString("US$"),
1518 UnicodeString(ucurr_getName(USD, "en_AU",
1519 UCURR_SYMBOL_NAME,
1520 &isChoiceFormat, &len, &ec)));
1521 assertEquals("CAD.getName(SYMBOL_NAME)",
1522 UnicodeString("Can$"),
1523 UnicodeString(ucurr_getName(CAD, "en_AU",
1524 UCURR_SYMBOL_NAME,
1525 &isChoiceFormat, &len, &ec)));
1526 assertEquals("USX.getName(LONG_NAME)",
1527 UnicodeString("USX"),
1528 UnicodeString(ucurr_getName(USX, "en_US",
1529 UCURR_LONG_NAME,
1530 &isChoiceFormat, &len, &ec)));
1531 assertSuccess("ucurr_getName", ec);
1532
1533 ec = U_ZERO_ERROR;
1534
1535 // Test that a default or fallback warning is being returned. JB 4239.
1536 ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat,
1537 &len, &ec);
1538 assertTrue("ucurr_getName (fallback)",
1539 U_USING_FALLBACK_WARNING == ec, TRUE);
1540
1541 ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat,
1542 &len, &ec);
1543 assertTrue("ucurr_getName (fallback)",
1544 U_USING_FALLBACK_WARNING == ec, TRUE);
1545
1546 ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
1547 &len, &ec);
1548 assertTrue("ucurr_getName (default)",
1549 U_USING_DEFAULT_WARNING == ec, TRUE);
1550
1551 ucurr_getName(CAD, "vi", UCURR_LONG_NAME, &isChoiceFormat,
1552 &len, &ec);
1553 assertTrue("ucurr_getName (default)",
1554 U_USING_DEFAULT_WARNING == ec, TRUE);
1555
1556 // Test that a default warning is being returned when falling back to root. JB 4536.
1557 ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
1558 &len, &ec);
1559 assertTrue("ucurr_getName (default to root)",
1560 U_USING_DEFAULT_WARNING == ec, TRUE);
1561
1562 // TODO add more tests later
1563 }
1564
TestCurrencyUnit(void)1565 void NumberFormatTest::TestCurrencyUnit(void){
1566 UErrorCode ec = U_ZERO_ERROR;
1567 static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
1568 CurrencyUnit cu(USD, ec);
1569 assertSuccess("CurrencyUnit", ec);
1570
1571 const UChar * r = cu.getISOCurrency(); // who is the buffer owner ?
1572 assertEquals("getISOCurrency()", USD, r);
1573
1574 CurrencyUnit cu2(cu);
1575 if (!(cu2 == cu)){
1576 errln("CurrencyUnit copy constructed object should be same");
1577 }
1578
1579 CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone();
1580 if (!(*cu3 == cu)){
1581 errln("CurrencyUnit cloned object should be same");
1582 }
1583 delete cu3;
1584 }
1585
TestCurrencyAmount(void)1586 void NumberFormatTest::TestCurrencyAmount(void){
1587 UErrorCode ec = U_ZERO_ERROR;
1588 static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
1589 CurrencyAmount ca(9, USD, ec);
1590 assertSuccess("CurrencyAmount", ec);
1591
1592 CurrencyAmount ca2(ca);
1593 if (!(ca2 == ca)){
1594 errln("CurrencyAmount copy constructed object should be same");
1595 }
1596
1597 ca2=ca;
1598 if (!(ca2 == ca)){
1599 errln("CurrencyAmount assigned object should be same");
1600 }
1601
1602 CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone();
1603 if (!(*ca3 == ca)){
1604 errln("CurrencyAmount cloned object should be same");
1605 }
1606 delete ca3;
1607 }
1608
TestSymbolsWithBadLocale(void)1609 void NumberFormatTest::TestSymbolsWithBadLocale(void) {
1610 Locale locDefault;
1611 Locale locBad("x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME");
1612 UErrorCode status = U_ZERO_ERROR;
1613 UnicodeString intlCurrencySymbol((UChar)0xa4);
1614
1615 intlCurrencySymbol.append((UChar)0xa4);
1616
1617 logln("Current locale is %s", Locale::getDefault().getName());
1618 Locale::setDefault(locBad, status);
1619 logln("Current locale is %s", Locale::getDefault().getName());
1620 DecimalFormatSymbols mySymbols(status);
1621 if (status != U_USING_FALLBACK_WARNING) {
1622 errln("DecimalFormatSymbols should returned U_USING_FALLBACK_WARNING.");
1623 }
1624 if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
1625 errln("DecimalFormatSymbols does not have the right locale.");
1626 }
1627 int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
1628 for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
1629 logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ")
1630 + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum)));
1631
1632 if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0
1633 && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
1634 && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
1635 {
1636 errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
1637 }
1638 }
1639 status = U_ZERO_ERROR;
1640 Locale::setDefault(locDefault, status);
1641 logln("Current locale is %s", Locale::getDefault().getName());
1642 }
1643
1644 /**
1645 * Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols
1646 * behave the same, except for memory ownership semantics. (No
1647 * version of this test on Java, since Java has only one method.)
1648 */
TestAdoptDecimalFormatSymbols(void)1649 void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) {
1650 UErrorCode ec = U_ZERO_ERROR;
1651 DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
1652 if (U_FAILURE(ec)) {
1653 errln("Fail: DecimalFormatSymbols constructor");
1654 delete sym;
1655 return;
1656 }
1657 UnicodeString pat(" #,##0.00");
1658 pat.insert(0, (UChar)0x00A4);
1659 DecimalFormat fmt(pat, sym, ec);
1660 if (U_FAILURE(ec)) {
1661 errln("Fail: DecimalFormat constructor");
1662 return;
1663 }
1664
1665 UnicodeString str;
1666 fmt.format(2350.75, str);
1667 if (str == "$ 2,350.75") {
1668 logln(str);
1669 } else {
1670 errln("Fail: " + str + ", expected $ 2,350.75");
1671 }
1672
1673 sym = new DecimalFormatSymbols(Locale::getUS(), ec);
1674 if (U_FAILURE(ec)) {
1675 errln("Fail: DecimalFormatSymbols constructor");
1676 delete sym;
1677 return;
1678 }
1679 sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
1680 fmt.adoptDecimalFormatSymbols(sym);
1681
1682 str.truncate(0);
1683 fmt.format(2350.75, str);
1684 if (str == "Q 2,350.75") {
1685 logln(str);
1686 } else {
1687 errln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
1688 }
1689
1690 sym = new DecimalFormatSymbols(Locale::getUS(), ec);
1691 if (U_FAILURE(ec)) {
1692 errln("Fail: DecimalFormatSymbols constructor");
1693 delete sym;
1694 return;
1695 }
1696 DecimalFormat fmt2(pat, sym, ec);
1697 if (U_FAILURE(ec)) {
1698 errln("Fail: DecimalFormat constructor");
1699 return;
1700 }
1701
1702 DecimalFormatSymbols sym2(Locale::getUS(), ec);
1703 if (U_FAILURE(ec)) {
1704 errln("Fail: DecimalFormatSymbols constructor");
1705 return;
1706 }
1707 sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
1708 fmt2.setDecimalFormatSymbols(sym2);
1709
1710 str.truncate(0);
1711 fmt2.format(2350.75, str);
1712 if (str == "Q 2,350.75") {
1713 logln(str);
1714 } else {
1715 errln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
1716 }
1717 }
1718
TestPerMill()1719 void NumberFormatTest::TestPerMill() {
1720 UErrorCode ec = U_ZERO_ERROR;
1721 UnicodeString str;
1722 DecimalFormat fmt(ctou("###.###\\u2030"), ec);
1723 if (!assertSuccess("DecimalFormat ct", ec)) return;
1724 assertEquals("0.4857 x ###.###\\u2030",
1725 ctou("485.7\\u2030"), fmt.format(0.4857, str));
1726
1727 DecimalFormatSymbols sym(Locale::getUS(), ec);
1728 sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
1729 DecimalFormat fmt2("", sym, ec);
1730 fmt2.applyLocalizedPattern("###.###m", ec);
1731 if (!assertSuccess("setup", ec)) return;
1732 str.truncate(0);
1733 assertEquals("0.4857 x ###.###m",
1734 "485.7m", fmt2.format(0.4857, str));
1735 }
1736
1737 /**
1738 * Generic test for patterns that should be legal/illegal.
1739 */
TestIllegalPatterns()1740 void NumberFormatTest::TestIllegalPatterns() {
1741 // Test cases:
1742 // Prefix with "-:" for illegal patterns
1743 // Prefix with "+:" for legal patterns
1744 const char* DATA[] = {
1745 // Unquoted special characters in the suffix are illegal
1746 "-:000.000|###",
1747 "+:000.000'|###'",
1748 0
1749 };
1750 for (int32_t i=0; DATA[i]; ++i) {
1751 const char* pat=DATA[i];
1752 UBool valid = (*pat) == '+';
1753 pat += 2;
1754 UErrorCode ec = U_ZERO_ERROR;
1755 DecimalFormat fmt(pat, ec); // locale doesn't matter here
1756 if (U_SUCCESS(ec) == valid) {
1757 logln("Ok: pattern \"%s\": %s",
1758 pat, u_errorName(ec));
1759 } else {
1760 errln("FAIL: pattern \"%s\" should have %s; got %s",
1761 pat, (valid?"succeeded":"failed"),
1762 u_errorName(ec));
1763 }
1764 }
1765 }
1766
1767 //----------------------------------------------------------------------
1768
1769 static const char* KEYWORDS[] = {
1770 /*0*/ "ref=", // <reference pattern to parse numbers>
1771 /*1*/ "loc=", // <locale for formats>
1772 /*2*/ "f:", // <pattern or '-'> <number> <exp. string>
1773 /*3*/ "fp:", // <pattern or '-'> <number> <exp. string> <exp. number>
1774 /*4*/ "rt:", // <pattern or '-'> <(exp.) number> <(exp.) string>
1775 /*5*/ "p:", // <pattern or '-'> <string> <exp. number>
1776 /*6*/ "perr:", // <pattern or '-'> <invalid string>
1777 /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
1778 /*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
1779 0
1780 };
1781
1782 /**
1783 * Return an integer representing the next token from this
1784 * iterator. The integer will be an index into the given list, or
1785 * -1 if there are no more tokens, or -2 if the token is not on
1786 * the list.
1787 */
keywordIndex(const UnicodeString & tok)1788 static int32_t keywordIndex(const UnicodeString& tok) {
1789 for (int32_t i=0; KEYWORDS[i]!=0; ++i) {
1790 if (tok==KEYWORDS[i]) {
1791 return i;
1792 }
1793 }
1794 return -1;
1795 }
1796
1797 /**
1798 * Parse a CurrencyAmount using the given NumberFormat, with
1799 * the 'delim' character separating the number and the currency.
1800 */
parseCurrencyAmount(const UnicodeString & str,const NumberFormat & fmt,UChar delim,Formattable & result,UErrorCode & ec)1801 static void parseCurrencyAmount(const UnicodeString& str,
1802 const NumberFormat& fmt,
1803 UChar delim,
1804 Formattable& result,
1805 UErrorCode& ec) {
1806 UnicodeString num, cur;
1807 int32_t i = str.indexOf(delim);
1808 str.extractBetween(0, i, num);
1809 str.extractBetween(i+1, INT32_MAX, cur);
1810 Formattable n;
1811 fmt.parse(num, n, ec);
1812 result.adoptObject(new CurrencyAmount(n, cur.getTerminatedBuffer(), ec));
1813 }
1814
TestCases()1815 void NumberFormatTest::TestCases() {
1816 UErrorCode ec = U_ZERO_ERROR;
1817 TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
1818 if (U_FAILURE(ec)) {
1819 errln("FAIL: Couldn't open NumberFormatTestCases.txt");
1820 return;
1821 }
1822 TokenIterator tokens(&reader);
1823
1824 Locale loc("en", "US", "");
1825 DecimalFormat *ref = 0, *fmt = 0;
1826 MeasureFormat *mfmt = 0;
1827 UnicodeString pat, tok, mloc, str, out, where, currAmt;
1828 Formattable n;
1829
1830 for (;;) {
1831 ec = U_ZERO_ERROR;
1832 if (!tokens.next(tok, ec)) {
1833 break;
1834 }
1835 where = UnicodeString("(") + tokens.getLineNumber() + ") ";
1836 int32_t cmd = keywordIndex(tok);
1837 switch (cmd) {
1838 case 0:
1839 // ref= <reference pattern>
1840 if (!tokens.next(tok, ec)) goto error;
1841 delete ref;
1842 ref = new DecimalFormat(tok,
1843 new DecimalFormatSymbols(Locale::getUS(), ec), ec);
1844 if (U_FAILURE(ec)) {
1845 dataerrln("Error constructing DecimalFormat");
1846 goto error;
1847 }
1848 break;
1849 case 1:
1850 // loc= <locale>
1851 if (!tokens.next(tok, ec)) goto error;
1852 loc = Locale::createFromName(CharString(tok));
1853 break;
1854 case 2: // f:
1855 case 3: // fp:
1856 case 4: // rt:
1857 case 5: // p:
1858 if (!tokens.next(tok, ec)) goto error;
1859 if (tok != "-") {
1860 pat = tok;
1861 delete fmt;
1862 fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec);
1863 if (U_FAILURE(ec)) {
1864 errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec));
1865 ec = U_ZERO_ERROR;
1866 if (!tokens.next(tok, ec)) goto error;
1867 if (!tokens.next(tok, ec)) goto error;
1868 if (cmd == 3) {
1869 if (!tokens.next(tok, ec)) goto error;
1870 }
1871 continue;
1872 }
1873 }
1874 if (cmd == 2 || cmd == 3 || cmd == 4) {
1875 // f: <pattern or '-'> <number> <exp. string>
1876 // fp: <pattern or '-'> <number> <exp. string> <exp. number>
1877 // rt: <pattern or '-'> <number> <string>
1878 UnicodeString num;
1879 if (!tokens.next(num, ec)) goto error;
1880 if (!tokens.next(str, ec)) goto error;
1881 ref->parse(num, n, ec);
1882 assertSuccess("parse", ec);
1883 assertEquals(where + "\"" + pat + "\".format(" + num + ")",
1884 str, fmt->format(n, out.remove(), ec));
1885 assertSuccess("format", ec);
1886 if (cmd == 3) { // fp:
1887 if (!tokens.next(num, ec)) goto error;
1888 ref->parse(num, n, ec);
1889 assertSuccess("parse", ec);
1890 }
1891 if (cmd != 2) { // != f:
1892 Formattable m;
1893 fmt->parse(str, m, ec);
1894 assertSuccess("parse", ec);
1895 assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
1896 n, m);
1897 }
1898 }
1899 // p: <pattern or '-'> <string to parse> <exp. number>
1900 else {
1901 UnicodeString expstr;
1902 if (!tokens.next(str, ec)) goto error;
1903 if (!tokens.next(expstr, ec)) goto error;
1904 Formattable exp, n;
1905 ref->parse(expstr, exp, ec);
1906 assertSuccess("parse", ec);
1907 fmt->parse(str, n, ec);
1908 assertSuccess("parse", ec);
1909 assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
1910 exp, n);
1911 }
1912 break;
1913 case 8: // fpc:
1914 if (!tokens.next(tok, ec)) goto error;
1915 if (tok != "-") {
1916 mloc = tok;
1917 delete mfmt;
1918 mfmt = MeasureFormat::createCurrencyFormat(
1919 Locale::createFromName(CharString(mloc)), ec);
1920 if (U_FAILURE(ec)) {
1921 errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec));
1922 ec = U_ZERO_ERROR;
1923 if (!tokens.next(tok, ec)) goto error;
1924 if (!tokens.next(tok, ec)) goto error;
1925 if (!tokens.next(tok, ec)) goto error;
1926 continue;
1927 }
1928 }
1929 // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
1930 if (!tokens.next(currAmt, ec)) goto error;
1931 if (!tokens.next(str, ec)) goto error;
1932 parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
1933 if (assertSuccess("parseCurrencyAmount", ec)) {
1934 assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
1935 str, mfmt->format(n, out.remove(), ec));
1936 assertSuccess("format", ec);
1937 }
1938 if (!tokens.next(currAmt, ec)) goto error;
1939 parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
1940 if (assertSuccess("parseCurrencyAmount", ec)) {
1941 Formattable m;
1942 mfmt->parseObject(str, m, ec);
1943 if (assertSuccess("parseCurrency", ec)) {
1944 assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
1945 n, m);
1946 }
1947 }
1948 break;
1949 case 6:
1950 // perr: <pattern or '-'> <invalid string>
1951 errln("FAIL: Under construction");
1952 goto done;
1953 case 7: {
1954 // pat: <pattern> <exp. toPattern, or '-' or 'err'>
1955 UnicodeString testpat;
1956 UnicodeString exppat;
1957 if (!tokens.next(testpat, ec)) goto error;
1958 if (!tokens.next(exppat, ec)) goto error;
1959 UBool err = exppat == "err";
1960 UBool existingPat = FALSE;
1961 if (testpat == "-") {
1962 if (err) {
1963 errln("FAIL: " + where + "Invalid command \"pat: - err\"");
1964 continue;
1965 }
1966 existingPat = TRUE;
1967 testpat = pat;
1968 }
1969 if (exppat == "-") exppat = testpat;
1970 DecimalFormat* f = 0;
1971 UErrorCode ec2 = U_ZERO_ERROR;
1972 if (existingPat) {
1973 f = fmt;
1974 } else {
1975 f = new DecimalFormat(testpat, ec2);
1976 }
1977 if (U_SUCCESS(ec2)) {
1978 if (err) {
1979 errln("FAIL: " + where + "Invalid pattern \"" + testpat +
1980 "\" was accepted");
1981 } else {
1982 UnicodeString pat2;
1983 assertEquals(where + "\"" + testpat + "\".toPattern()",
1984 exppat, f->toPattern(pat2));
1985 }
1986 } else {
1987 if (err) {
1988 logln("Ok: " + where + "Invalid pattern \"" + testpat +
1989 "\" failed: " + u_errorName(ec2));
1990 } else {
1991 errln("FAIL: " + where + "Valid pattern \"" + testpat +
1992 "\" failed: " + u_errorName(ec2));
1993 }
1994 }
1995 if (!existingPat) delete f;
1996 } break;
1997 case -1:
1998 errln("FAIL: " + where + "Unknown command \"" + tok + "\"");
1999 goto done;
2000 }
2001 }
2002 goto done;
2003
2004 error:
2005 if (U_SUCCESS(ec)) {
2006 errln("FAIL: Unexpected EOF");
2007 } else {
2008 errln("FAIL: " + where + "Unexpected " + u_errorName(ec));
2009 }
2010
2011 done:
2012 delete mfmt;
2013 delete fmt;
2014 delete ref;
2015 }
2016
2017
2018 //----------------------------------------------------------------------
2019 // Support methods
2020 //----------------------------------------------------------------------
2021
equalValue(const Formattable & a,const Formattable & b)2022 UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) {
2023 if (a.getType() == b.getType()) {
2024 return a == b;
2025 }
2026
2027 if (a.getType() == Formattable::kLong) {
2028 if (b.getType() == Formattable::kInt64) {
2029 return a.getLong() == b.getLong();
2030 } else if (b.getType() == Formattable::kDouble) {
2031 return (double) a.getLong() == b.getDouble(); // TODO check use of double instead of long
2032 }
2033 } else if (a.getType() == Formattable::kDouble) {
2034 if (b.getType() == Formattable::kLong) {
2035 return a.getDouble() == (double) b.getLong();
2036 } else if (b.getType() == Formattable::kInt64) {
2037 return a.getDouble() == (double)b.getInt64();
2038 }
2039 } else if (a.getType() == Formattable::kInt64) {
2040 if (b.getType() == Formattable::kLong) {
2041 return a.getInt64() == (int64_t)b.getLong();
2042 } else if (b.getType() == Formattable::kDouble) {
2043 return a.getInt64() == (int64_t)b.getDouble();
2044 }
2045 }
2046 return FALSE;
2047 }
2048
expect2(NumberFormat & fmt,const Formattable & n,const UnicodeString & str)2049 void NumberFormatTest::expect2(NumberFormat& fmt, const Formattable& n, const UnicodeString& str) {
2050 // Don't round-trip format test, since we explicitly do it
2051 expect(fmt, n, str, FALSE);
2052 expect(fmt, str, n);
2053 }
2054
expect2(NumberFormat * fmt,const Formattable & n,const UnicodeString & exp,UErrorCode status)2055 void NumberFormatTest::expect2(NumberFormat* fmt, const Formattable& n,
2056 const UnicodeString& exp,
2057 UErrorCode status) {
2058 if (U_FAILURE(status)) {
2059 errln("FAIL: NumberFormat constructor");
2060 } else {
2061 expect2(*fmt, n, exp);
2062 }
2063 delete fmt;
2064 }
2065
expect(NumberFormat & fmt,const UnicodeString & str,const Formattable & n)2066 void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const Formattable& n) {
2067 UErrorCode status = U_ZERO_ERROR;
2068 Formattable num;
2069 fmt.parse(str, num, status);
2070 if (U_FAILURE(status)) {
2071 errln(UnicodeString("FAIL: Parse failed for \"") + str + "\"");
2072 return;
2073 }
2074 UnicodeString pat;
2075 ((DecimalFormat*) &fmt)->toPattern(pat);
2076 if (equalValue(num, n)) {
2077 logln(UnicodeString("Ok \"") + str + "\" x " +
2078 pat + " = " +
2079 toString(num));
2080 } else {
2081 errln(UnicodeString("FAIL \"") + str + "\" x " +
2082 pat + " = " +
2083 toString(num) + ", expected " + toString(n));
2084 }
2085 }
2086
expect(NumberFormat & fmt,const Formattable & n,const UnicodeString & exp,UBool rt)2087 void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n,
2088 const UnicodeString& exp, UBool rt) {
2089 UnicodeString saw;
2090 FieldPosition pos;
2091 UErrorCode status = U_ZERO_ERROR;
2092 fmt.format(n, saw, pos, status);
2093 CHECK(status, "NumberFormat::format");
2094 UnicodeString pat;
2095 ((DecimalFormat*) &fmt)->toPattern(pat);
2096 if (saw == exp) {
2097 logln(UnicodeString("Ok ") + toString(n) + " x " +
2098 escape(pat) + " = \"" +
2099 escape(saw) + "\"");
2100 // We should be able to round-trip the formatted string =>
2101 // number => string (but not the other way around: number
2102 // => string => number2, might have number2 != number):
2103 if (rt) {
2104 Formattable n2;
2105 fmt.parse(exp, n2, status);
2106 if (U_FAILURE(status)) {
2107 errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\"");
2108 return;
2109 }
2110 UnicodeString saw2;
2111 fmt.format(n2, saw2, pos, status);
2112 CHECK(status, "NumberFormat::format");
2113 if (saw2 != exp) {
2114 errln((UnicodeString)"FAIL \"" + exp + "\" => " + toString(n2) +
2115 " => \"" + saw2 + "\"");
2116 }
2117 }
2118 } else {
2119 errln(UnicodeString("FAIL ") + toString(n) + " x " +
2120 escape(pat) + " = \"" +
2121 escape(saw) + "\", expected \"" + exp + "\"");
2122 }
2123 }
2124
expect(NumberFormat * fmt,const Formattable & n,const UnicodeString & exp,UErrorCode status)2125 void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n,
2126 const UnicodeString& exp,
2127 UErrorCode status) {
2128 if (U_FAILURE(status)) {
2129 errln("FAIL: NumberFormat constructor");
2130 } else {
2131 expect(*fmt, n, exp);
2132 }
2133 delete fmt;
2134 }
2135
expectCurrency(NumberFormat & nf,const Locale & locale,double value,const UnicodeString & string)2136 void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale,
2137 double value, const UnicodeString& string) {
2138 UErrorCode ec = U_ZERO_ERROR;
2139 DecimalFormat& fmt = * (DecimalFormat*) &nf;
2140 const UChar DEFAULT_CURR[] = {45/*-*/,0};
2141 UChar curr[4];
2142 u_strcpy(curr, DEFAULT_CURR);
2143 if (*locale.getLanguage() != 0) {
2144 ucurr_forLocale(locale.getName(), curr, 4, &ec);
2145 assertSuccess("ucurr_forLocale", ec);
2146 fmt.setCurrency(curr, ec);
2147 assertSuccess("DecimalFormat::setCurrency", ec);
2148 fmt.setCurrency(curr); //Deprecated variant, for coverage only
2149 }
2150 UnicodeString s;
2151 fmt.format(value, s);
2152 s.findAndReplace((UChar32)0x00A0, (UChar32)0x0020);
2153
2154 // Default display of the number yields "1234.5599999999999"
2155 // instead of "1234.56". Use a formatter to fix this.
2156 NumberFormat* f =
2157 NumberFormat::createInstance(Locale::getUS(), ec);
2158 UnicodeString v;
2159 if (U_FAILURE(ec)) {
2160 // Oops; bad formatter. Use default op+= display.
2161 v = (UnicodeString)"" + value;
2162 } else {
2163 f->setMaximumFractionDigits(4);
2164 f->setGroupingUsed(FALSE);
2165 f->format(value, v);
2166 }
2167 delete f;
2168
2169 if (s == string) {
2170 logln((UnicodeString)"Ok: " + v + " x " + curr + " => " + prettify(s));
2171 } else {
2172 errln((UnicodeString)"FAIL: " + v + " x " + curr + " => " + prettify(s) +
2173 ", expected " + prettify(string));
2174 }
2175 }
2176
expectPat(DecimalFormat & fmt,const UnicodeString & exp)2177 void NumberFormatTest::expectPat(DecimalFormat& fmt, const UnicodeString& exp) {
2178 UnicodeString pat;
2179 fmt.toPattern(pat);
2180 if (pat == exp) {
2181 logln(UnicodeString("Ok \"") + pat + "\"");
2182 } else {
2183 errln(UnicodeString("FAIL \"") + pat + "\", expected \"" + exp + "\"");
2184 }
2185 }
2186
expectPad(DecimalFormat & fmt,const UnicodeString & pat,int32_t pos)2187 void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
2188 int32_t pos) {
2189 expectPad(fmt, pat, pos, 0, (UnicodeString)"");
2190 }
expectPad(DecimalFormat & fmt,const UnicodeString & pat,int32_t pos,int32_t width,UChar pad)2191 void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
2192 int32_t pos, int32_t width, UChar pad) {
2193 expectPad(fmt, pat, pos, width, UnicodeString(pad));
2194 }
expectPad(DecimalFormat & fmt,const UnicodeString & pat,int32_t pos,int32_t width,const UnicodeString & pad)2195 void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
2196 int32_t pos, int32_t width, const UnicodeString& pad) {
2197 int32_t apos = 0, awidth = 0;
2198 UnicodeString apadStr;
2199 UErrorCode status = U_ZERO_ERROR;
2200 fmt.applyPattern(pat, status);
2201 if (U_SUCCESS(status)) {
2202 apos = fmt.getPadPosition();
2203 awidth = fmt.getFormatWidth();
2204 apadStr=fmt.getPadCharacterString();
2205 } else {
2206 apos = -1;
2207 awidth = width;
2208 apadStr = pad;
2209 }
2210 if (apos == pos && awidth == width && apadStr == pad) {
2211 UnicodeString infoStr;
2212 if (pos == ILLEGAL) {
2213 infoStr = UnicodeString(" width=", "") + awidth + UnicodeString(" pad=", "") + apadStr;
2214 }
2215 logln(UnicodeString("Ok \"") + pat + "\" pos=" + apos + infoStr);
2216 } else {
2217 errln(UnicodeString("FAIL \"") + pat + "\" pos=" + apos +
2218 " width=" + awidth + " pad=" + apadStr +
2219 ", expected " + pos + " " + width + " " + pad);
2220 }
2221 }
TestJB3832()2222 void NumberFormatTest::TestJB3832(){
2223 const char* localeID = "pt_PT@currency=PTE";
2224 Locale loc(localeID);
2225 UErrorCode status = U_ZERO_ERROR;
2226 UnicodeString expected("1,150$50 Esc.");
2227 UnicodeString s;
2228 NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status);
2229 if(U_FAILURE(status)){
2230 errln("Could not create currency formatter for locale %s", localeID);
2231 return;
2232 }
2233 currencyFmt->format(1150.50, s);
2234 if(s!=expected){
2235 errln(UnicodeString("FAIL: Expected: ")+expected
2236 + UnicodeString(" Got: ") + s
2237 + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
2238 }
2239 if (U_FAILURE(status)){
2240 errln("FAIL: Status %s", u_errorName(status));
2241 }
2242 delete currencyFmt;
2243 }
2244
TestHost()2245 void NumberFormatTest::TestHost()
2246 {
2247 #ifdef U_WINDOWS
2248 Win32NumberTest::testLocales(this);
2249 #endif
2250 }
2251
TestHostClone()2252 void NumberFormatTest::TestHostClone()
2253 {
2254 /*
2255 Verify that a cloned formatter gives the same results
2256 and is useable after the original has been deleted.
2257 */
2258 // This is mainly important on Windows.
2259 UErrorCode status = U_ZERO_ERROR;
2260 Locale loc("en_US@compat=host");
2261 UDate now = Calendar::getNow();
2262 NumberFormat *full = NumberFormat::createInstance(loc, status);
2263 if (full == NULL || U_FAILURE(status)) {
2264 errln("FAIL: Can't create Relative date instance");
2265 return;
2266 }
2267 UnicodeString result1;
2268 full->format(now, result1, status);
2269 Format *fullClone = full->clone();
2270 delete full;
2271 full = NULL;
2272
2273 UnicodeString result2;
2274 fullClone->format(now, result2, status);
2275 if (U_FAILURE(status)) {
2276 errln("FAIL: format failure.");
2277 }
2278 if (result1 != result2) {
2279 errln("FAIL: Clone returned different result from non-clone.");
2280 }
2281 delete fullClone;
2282 }
2283
TestCurrencyFormat()2284 void NumberFormatTest::TestCurrencyFormat()
2285 {
2286 // This test is here to increase code coverage.
2287 UErrorCode status = U_ZERO_ERROR;
2288 MeasureFormat *cloneObj;
2289 UnicodeString str;
2290 Formattable toFormat, result;
2291 static const UChar ISO_CODE[4] = {0x0047, 0x0042, 0x0050, 0};
2292
2293 Locale saveDefaultLocale = Locale::getDefault();
2294 Locale::setDefault( Locale::getUK(), status );
2295 if (U_FAILURE(status)) {
2296 errln("couldn't set default Locale!");
2297 return;
2298 }
2299
2300 MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status);
2301 Locale::setDefault( saveDefaultLocale, status );
2302 if (U_FAILURE(status)){
2303 errln("FAIL: Status %s", u_errorName(status));
2304 return;
2305 }
2306 cloneObj = (MeasureFormat *)measureObj->clone();
2307 if (cloneObj == NULL) {
2308 errln("Clone doesn't work");
2309 return;
2310 }
2311 toFormat.adoptObject(new CurrencyAmount(1234.56, ISO_CODE, status));
2312 measureObj->format(toFormat, str, status);
2313 measureObj->parseObject(str, result, status);
2314 if (U_FAILURE(status)){
2315 errln("FAIL: Status %s", u_errorName(status));
2316 }
2317 if (result != toFormat) {
2318 errln("measureObj does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
2319 }
2320 status = U_ZERO_ERROR;
2321 str.truncate(0);
2322 cloneObj->format(toFormat, str, status);
2323 cloneObj->parseObject(str, result, status);
2324 if (U_FAILURE(status)){
2325 errln("FAIL: Status %s", u_errorName(status));
2326 }
2327 if (result != toFormat) {
2328 errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
2329 }
2330 if (*measureObj != *cloneObj) {
2331 errln("Cloned object is not equal to the original object");
2332 }
2333 delete measureObj;
2334 delete cloneObj;
2335
2336 status = U_USELESS_COLLATOR_ERROR;
2337 if (MeasureFormat::createCurrencyFormat(status) != NULL) {
2338 errln("createCurrencyFormat should have returned NULL.");
2339 }
2340 }
2341
2342 /* Port of ICU4J rounding test. */
TestRounding()2343 void NumberFormatTest::TestRounding() {
2344 UErrorCode status = U_ZERO_ERROR;
2345 DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
2346
2347 if (U_FAILURE(status)) {
2348 errln("Unable to create decimal formatter.");
2349 return;
2350 }
2351
2352 int roundingIncrements[]={1, 2, 5, 20, 50, 100};
2353 int testValues[]={0, 300};
2354
2355 for (int j=0; j<2; j++) {
2356 for (int mode=DecimalFormat::kRoundUp;mode<DecimalFormat::kRoundHalfEven;mode++) {
2357 df->setRoundingMode((DecimalFormat::ERoundingMode)mode);
2358 for (int increment=0; increment<6; increment++) {
2359 double base=testValues[j];
2360 double rInc=roundingIncrements[increment];
2361 checkRounding(df, base, 20, rInc);
2362 rInc=1.000000000/rInc;
2363 checkRounding(df, base, 20, rInc);
2364 }
2365 }
2366 }
2367
2368 }
2369
checkRounding(DecimalFormat * df,double base,int iterations,double increment)2370 void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) {
2371 df->setRoundingIncrement(increment);
2372 double lastParsed=INT32_MIN; //Intger.MIN_VALUE
2373 for (int i=-iterations; i<=iterations;i++) {
2374 double iValue=base+(increment*(i*0.1));
2375 double smallIncrement=0.00000001;
2376 if (iValue!=0) {
2377 smallIncrement*=iValue;
2378 }
2379 //we not only test the value, but some values in a small range around it
2380 lastParsed=checkRound(df, iValue-smallIncrement, lastParsed);
2381 lastParsed=checkRound(df, iValue, lastParsed);
2382 lastParsed=checkRound(df, iValue+smallIncrement, lastParsed);
2383 }
2384 }
2385
checkRound(DecimalFormat * df,double iValue,double lastParsed)2386 double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) {
2387 UErrorCode status=U_ZERO_ERROR;
2388 UnicodeString formattedDecimal;
2389 double parsed;
2390 Formattable result;
2391 df->format(iValue, formattedDecimal, status);
2392
2393 if (U_FAILURE(status)) {
2394 errln("Error formatting number.");
2395 }
2396
2397 df->parse(formattedDecimal, result, status);
2398
2399 if (U_FAILURE(status)) {
2400 errln("Error parsing number.");
2401 }
2402
2403 parsed=result.getDouble();
2404
2405 if (lastParsed>parsed) {
2406 errln("Rounding wrong direction! %d > %d", lastParsed, parsed);
2407 }
2408
2409 return lastParsed;
2410 }
2411
2412 #endif /* #if !UCONFIG_NO_FORMATTING */
2413