]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tsnmfmt.cpp
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /***********************************************************************
5 * Copyright (c) 1997-2012, International Business Machines Corporation
6 * and others. All Rights Reserved.
7 ***********************************************************************/
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/decimfmt.h"
20 IntlTestNumberFormat::~IntlTestNumberFormat() {}
22 static const char * formattableTypeName(Formattable::Type t
)
25 case Formattable::kDate
: return "kDate";
26 case Formattable::kDouble
: return "kDouble";
27 case Formattable::kLong
: return "kLong";
28 case Formattable::kString
: return "kString";
29 case Formattable::kArray
: return "kArray";
30 case Formattable::kInt64
: return "kInt64";
31 default: return "??unknown??";
36 * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
39 void IntlTestNumberFormat::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
42 if (exec
) logln((UnicodeString
)"TestSuite NumberFormat");
44 case 0: name
= "createInstance";
48 fStatus
= U_ZERO_ERROR
;
49 fFormat
= NumberFormat::createInstance(fStatus
);
54 case 1: name
= "DefaultLocale";
55 if (exec
) testLocale(/*par, */Locale::getDefault(), name
);
58 case 2: name
= "testAvailableLocales";
61 testAvailableLocales(/*par*/);
65 case 3: name
= "monsterTest";
72 default: name
= ""; break;
77 IntlTestNumberFormat::testLocale(/* char* par, */const Locale
& locale
, const UnicodeString
& localeName
)
83 logln((UnicodeString
)name
+ " (" + localeName
+ ")");
84 fStatus
= U_ZERO_ERROR
;
85 fFormat
= NumberFormat::createInstance(locale
, fStatus
);
86 testFormat(/* par */);
88 name
= "Currency test";
89 logln((UnicodeString
)name
+ " (" + localeName
+ ")");
90 fStatus
= U_ZERO_ERROR
;
91 fFormat
= NumberFormat::createCurrencyInstance(locale
, fStatus
);
92 testFormat(/* par */);
94 name
= "Percent test";
95 logln((UnicodeString
)name
+ " (" + localeName
+ ")");
96 fStatus
= U_ZERO_ERROR
;
97 fFormat
= NumberFormat::createPercentInstance(locale
, fStatus
);
98 testFormat(/* par */);
100 if (uprv_strcmp(locale
.getName(), "en_US_POSIX") != 0) {
101 name
= "Scientific test";
102 logln((UnicodeString
)name
+ " (" + localeName
+ ")");
103 fStatus
= U_ZERO_ERROR
;
104 fFormat
= NumberFormat::createScientificInstance(locale
, fStatus
);
105 testFormat(/* par */);
109 double IntlTestNumberFormat::randDouble()
111 // Assume 8-bit (or larger) rand values. Also assume
112 // that the system rand() function is very poor, which it always is.
113 // Call srand(currentTime) in intltest to make it truly random.
116 char* poke
= (char*)&d
;
118 for (i
=0; i
< sizeof(double); ++i
)
120 poke
[i
] = (char)(rand() & 0xFF);
122 } while (uprv_isNaN(d
) || uprv_isInfinite(d
)
123 || !((-DBL_MAX
< d
&& d
< DBL_MAX
) || (d
< -DBL_MIN
&& DBL_MIN
< d
)));
129 * Return a random uint32_t
131 uint32_t IntlTestNumberFormat::randLong()
133 // Assume 8-bit (or larger) rand values. Also assume
134 // that the system rand() function is very poor, which it always is.
135 // Call srand(currentTime) in intltest to make it truly random.
138 char* poke
= (char*)&d
;
139 for (i
=0; i
< sizeof(uint32_t); ++i
)
141 poke
[i
] = (char)(rand() & 0xFF);
147 /* Make sure that we don't get something too large and multiply into infinity.
148 @param smallerThanMax the requested maximum value smaller than DBL_MAX */
149 double IntlTestNumberFormat::getSafeDouble(double smallerThanMax
) {
151 double high
= (DBL_MAX
/smallerThanMax
)/10.0;
155 } while (low
> it
|| it
> high
);
160 IntlTestNumberFormat::testFormat(/* char* par */)
162 if (U_FAILURE(fStatus
))
164 dataerrln((UnicodeString
)"**** FAIL: createXxxInstance failed. - " + u_errorName(fStatus
));
166 errln("**** FAIL: Non-null format returned by createXxxInstance upon failure.");
174 errln((UnicodeString
)"**** FAIL: Null format returned by createXxxInstance.");
180 // Assume it's a DecimalFormat and get some info
181 DecimalFormat
*s
= (DecimalFormat
*)fFormat
;
182 logln((UnicodeString
)" Pattern " + s
->toPattern(str
));
184 #if U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400
185 tryIt(-2.02147304840132e-68);
186 tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac
187 tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent
188 tryIt(9.29526819488338e+64); // Ok -- used to fail?
190 tryIt(-2.02147304840132e-100);
191 tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac
192 tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent
193 tryIt(9.29526819488338e+250); // Ok -- used to fail?
196 // These PASS now, with the sprintf/atof based format-parse.
198 // These fail due to round-off
199 // The least significant digit drops by one during each format-parse cycle.
200 // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %)
201 #if U_PLATFORM == U_PF_OS390
202 tryIt(-9.18228054496402e+64);
203 tryIt(-9.69413034454191e+64);
205 tryIt(-9.18228054496402e+255);
206 tryIt(-9.69413034454191e+273);
209 #if U_PLATFORM != U_PF_OS390
213 tryIt(uprv_getNaN());
214 tryIt(uprv_getInfinity());
215 tryIt(-uprv_getInfinity());
218 tryIt((int32_t)251887531);
222 tryIt(9.99999999999996);
223 tryIt(9.999999999999996);
227 tryIt((int32_t)INT32_MIN
);
228 tryIt((int32_t)INT32_MAX
);
229 tryIt((double)INT32_MIN
);
230 tryIt((double)INT32_MAX
);
231 tryIt((double)INT32_MIN
- 1.0);
232 tryIt((double)INT32_MAX
+ 1.0);
234 tryIt(5.0 / 9.0 * 1e-20);
235 tryIt(4.0 / 9.0 * 1e-20);
236 tryIt(5.0 / 9.0 * 1e+20);
237 tryIt(4.0 / 9.0 * 1e+20);
247 tryIt((int32_t)-100);
248 tryIt((int32_t)-1913860352);
250 for (int32_t z
=0; z
<10; ++z
)
252 double d
= randFraction() * 2e10
- 1e10
;
256 double it
= getSafeDouble(100000.0);
261 tryIt(uprv_floor(it
));
262 tryIt((int32_t)randLong());
265 it
= getSafeDouble(100.0);
267 tryIt(uprv_floor(it
));
268 tryIt((int32_t)randLong());
270 // try again with very large numbers
271 it
= getSafeDouble(100000000000.0);
274 // try again with very large numbers
275 // and without going outside of the int32_t range
276 it
= randFraction() * INT32_MAX
;
278 tryIt((int32_t)uprv_floor(it
));
284 IntlTestNumberFormat::tryIt(double aNumber
)
286 const int32_t DEPTH
= 10;
287 Formattable number
[DEPTH
];
288 UnicodeString string
[DEPTH
];
290 int32_t numberMatch
= 0;
291 int32_t stringMatch
= 0;
292 UnicodeString errMsg
;
294 for (i
=0; i
<DEPTH
; ++i
)
296 errMsg
.truncate(0); // if non-empty, we failed this iteration
297 UErrorCode status
= U_ZERO_ERROR
;
298 string
[i
] = "(n/a)"; // "format was never done" value
300 number
[i
].setDouble(aNumber
);
302 fFormat
->parse(string
[i
-1], number
[i
], status
);
303 if (U_FAILURE(status
)) {
304 number
[i
].setDouble(1234.5); // "parse failed" value
305 errMsg
= "**** FAIL: Parse of " + prettify(string
[i
-1]) + " failed.";
306 --i
; // don't show empty last line: "1234.5 F> (n/a) P>"
310 // Convert from long to double
311 if (number
[i
].getType() == Formattable::kLong
)
312 number
[i
].setDouble(number
[i
].getLong());
313 else if (number
[i
].getType() == Formattable::kInt64
)
314 number
[i
].setDouble((double)number
[i
].getInt64());
315 else if (number
[i
].getType() != Formattable::kDouble
)
317 errMsg
= ("**** FAIL: Parse of " + prettify(string
[i
-1])
318 + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number
[i
].getType()))
319 + ", Locale=" + UnicodeString(fLocale
.getName())
320 + ", longValue=" + number
[i
].getLong());
323 string
[i
].truncate(0);
324 fFormat
->format(number
[i
].getDouble(), string
[i
]);
327 if (numberMatch
== 0 && number
[i
] == number
[i
-1])
329 else if (numberMatch
> 0 && number
[i
] != number
[i
-1])
331 errMsg
= ("**** FAIL: Numeric mismatch after match.");
334 if (stringMatch
== 0 && string
[i
] == string
[i
-1])
336 else if (stringMatch
> 0 && string
[i
] != string
[i
-1])
338 errMsg
= ("**** FAIL: String mismatch after match.");
342 if (numberMatch
> 0 && stringMatch
> 0)
348 if (stringMatch
> 2 || numberMatch
> 2)
350 errMsg
= ("**** FAIL: No string and/or number match within 2 iterations.");
353 if (errMsg
.length() != 0)
355 for (int32_t k
=0; k
<=i
; ++k
)
357 logln((UnicodeString
)"" + k
+ ": " + number
[k
].getDouble() + " F> " +
358 prettify(string
[k
]) + " P> ");
365 IntlTestNumberFormat::tryIt(int32_t aNumber
)
367 Formattable
number(aNumber
);
368 UnicodeString stringNum
;
369 UErrorCode status
= U_ZERO_ERROR
;
371 fFormat
->format(number
, stringNum
, status
);
372 if (U_FAILURE(status
))
374 errln(UnicodeString("**** FAIL: Formatting ") + aNumber
);
377 fFormat
->parse(stringNum
, number
, status
);
378 if (U_FAILURE(status
))
380 errln("**** FAIL: Parse of " + prettify(stringNum
) + " failed.");
383 if (number
.getType() != Formattable::kLong
)
385 errln("**** FAIL: Parse of " + prettify(stringNum
)
386 + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number
.getType()))
387 + ", Locale=" + UnicodeString(fLocale
.getName())
388 + ", doubleValue=" + number
.getDouble()
389 + ", longValue=" + number
.getLong()
390 + ", origValue=" + aNumber
393 if (number
.getLong() != aNumber
) {
394 errln("**** FAIL: Parse of " + prettify(stringNum
) + " failed. Got:" + number
.getLong()
395 + " Expected:" + aNumber
);
399 void IntlTestNumberFormat::testAvailableLocales(/* char* par */)
402 const Locale
* locales
= NumberFormat::getAvailableLocales(count
);
403 logln((UnicodeString
)"" + count
+ " available locales");
404 if (locales
&& count
)
408 for (int32_t i
=0; i
<count
; ++i
)
412 all
+= locales
[i
].getName();
417 dataerrln((UnicodeString
)"**** FAIL: Zero available locales or null array pointer");
420 void IntlTestNumberFormat::monsterTest(/* char* par */)
422 const char *SEP
= "============================================================\n";
424 const Locale
* allLocales
= NumberFormat::getAvailableLocales(count
);
425 Locale
* locales
= (Locale
*)allLocales
;
426 Locale quickLocales
[6];
427 if (allLocales
&& count
)
429 if (quick
&& count
> 6) {
430 logln("quick test: testing just 6 locales!");
432 locales
= quickLocales
;
433 locales
[0] = allLocales
[0];
434 locales
[1] = allLocales
[1];
435 locales
[2] = allLocales
[2];
436 // In a quick test, make sure we test locales that use
437 // currency prefix, currency suffix, and choice currency
438 // logic. Otherwise bugs in these areas can slip through.
439 locales
[3] = Locale("ar", "AE", "");
440 locales
[4] = Locale("cs", "CZ", "");
441 locales
[5] = Locale("en", "IN", "");
443 for (int32_t i
=0; i
<count
; ++i
)
445 UnicodeString
name(locales
[i
].getName(), "");
447 testLocale(/* par, */locales
[i
], name
);
454 #endif /* #if !UCONFIG_NO_FORMATTING */