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