summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp')
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp2412
1 files changed, 2412 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp
new file mode 100644
index 00000000000..14d8f113ce6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp
@@ -0,0 +1,2412 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/* Modification History:
+* Date Name Description
+* 07/15/99 helena Ported to HPUX 10/11 CC.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "numfmtst.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/ustring.h"
+#include "unicode/measfmt.h"
+#include "unicode/curramt.h"
+#include "digitlst.h"
+#include "textfile.h"
+#include "tokiter.h"
+#include "charstr.h"
+#include "putilimp.h"
+#include "winnmtst.h"
+#include <float.h>
+#include <string.h>
+
+static const UChar EUR[] = {69,85,82,0}; // "EUR"
+
+// *****************************************************************************
+// class NumberFormatTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+#define CHECK(status,str) if (U_FAILURE(status)) { errln(UnicodeString("FAIL: ") + str); return; }
+
+void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite DateFormatTest");
+ switch (index) {
+ CASE(0,TestCurrencySign);
+ CASE(1,TestCurrency);
+ CASE(2,TestParse);
+ CASE(3,TestRounding487);
+ CASE(4,TestQuotes);
+ CASE(5,TestExponential);
+ CASE(6,TestPatterns);
+
+ // Upgrade to alphaWorks - liu 5/99
+ CASE(7,TestExponent);
+ CASE(8,TestScientific);
+ CASE(9,TestPad);
+ CASE(10,TestPatterns2);
+ CASE(11,TestSecondaryGrouping);
+ CASE(12,TestSurrogateSupport);
+ CASE(13,TestAPI);
+
+ CASE(14,TestCurrencyObject);
+ CASE(15,TestCurrencyPatterns);
+ //CASE(16,TestDigitList);
+ CASE(16,TestWhiteSpaceParsing);
+ CASE(17,TestComplexCurrency);
+ CASE(18,TestRegCurrency);
+ CASE(19,TestSymbolsWithBadLocale);
+ CASE(20,TestAdoptDecimalFormatSymbols);
+
+ CASE(21,TestScientific2);
+ CASE(22,TestScientificGrouping);
+ CASE(23,TestInt64);
+
+ CASE(24,TestPerMill);
+ CASE(25,TestIllegalPatterns);
+ CASE(26,TestCases);
+
+ CASE(27,TestCurrencyNames);
+ CASE(28,TestCurrencyAmount);
+ CASE(29,TestCurrencyUnit);
+ CASE(30,TestCoverage);
+ CASE(31,TestJB3832);
+ CASE(32,TestHost);
+ CASE(33,TestHostClone);
+ CASE(34,TestCurrencyFormat);
+ CASE(35,TestRounding);
+ default: name = ""; break;
+ }
+}
+
+// -------------------------------------
+
+// Test API (increase code coverage)
+void
+NumberFormatTest::TestAPI(void)
+{
+ logln("Test API");
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *test = NumberFormat::createInstance("root", status);
+ if(U_FAILURE(status)) {
+ errln("unable to create format object");
+ }
+ if(test != NULL) {
+ test->setMinimumIntegerDigits(10);
+ test->setMaximumIntegerDigits(2);
+
+ test->setMinimumFractionDigits(10);
+ test->setMaximumFractionDigits(2);
+
+ UnicodeString result;
+ FieldPosition pos;
+ Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers
+ test->format(bla, result, pos, status);
+ if(U_SUCCESS(status)) {
+ errln("Yuck... Formatted a duck... As a number!");
+ } else {
+ status = U_ZERO_ERROR;
+ }
+
+ result.remove();
+ int64_t ll = 12;
+ test->format(ll, result);
+ if (result != "12.00"){
+ errln("format int64_t error");
+ }
+
+ delete test;
+ }
+}
+
+class StubNumberForamt :public NumberFormat{
+public:
+ StubNumberForamt(){};
+ virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const {
+ return appendTo;
+ }
+ virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const {
+ return appendTo.append((UChar)0x0033);
+ }
+ virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const {
+ return NumberFormat::format(number, appendTo, pos);
+ }
+ virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const {
+ return appendTo;
+ }
+ virtual void parse(const UnicodeString& ,
+ Formattable& ,
+ ParsePosition& ) const {}
+ virtual void parse( const UnicodeString& ,
+ Formattable& ,
+ UErrorCode& ) const {}
+ virtual UClassID getDynamicClassID(void) const {
+ static char classID = 0;
+ return (UClassID)&classID;
+ }
+ virtual Format* clone() const {return NULL;}
+};
+
+void
+NumberFormatTest::TestCoverage(void){
+ StubNumberForamt stub;
+ UnicodeString agent("agent");
+ FieldPosition pos;
+ int64_t num = 4;
+ if (stub.format(num, agent, pos) != UnicodeString("agent3")){
+ errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)");
+ };
+}
+
+// Test various patterns
+void
+NumberFormatTest::TestPatterns(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ if (U_FAILURE(status)) { errln("FAIL: Could not construct DecimalFormatSymbols"); return; }
+
+ const char* pat[] = { "#.#", "#.", ".#", "#" };
+ int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
+ const char* newpat[] = { "#0.#", "#0.", "#.0", "#" };
+ const char* num[] = { "0", "0.", ".0", "0" };
+ for (int32_t i=0; i<pat_length; ++i)
+ {
+ status = U_ZERO_ERROR;
+ DecimalFormat fmt(pat[i], sym, status);
+ if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; }
+ UnicodeString newp; fmt.toPattern(newp);
+ if (!(newp == newpat[i]))
+ errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
+ "; " + newp + " seen instead");
+
+ UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s);
+ if (!(s == num[i]))
+ {
+ errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
+ "; " + s + " seen instead");
+ logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits());
+ }
+ }
+}
+
+/*
+icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
+icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
+icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
+*/
+/*
+void
+NumberFormatTest::TestDigitList(void)
+{
+ // API coverage for DigitList
+ DigitList list1;
+ list1.append('1');
+ list1.fDecimalAt = 1;
+ DigitList list2;
+ list2.set((int32_t)1);
+ if (list1 != list2) {
+ errln("digitlist append, operator!= or set failed ");
+ }
+ if (!(list1 == list2)) {
+ errln("digitlist append, operator== or set failed ");
+ }
+}
+*/
+
+// -------------------------------------
+
+// Test exponential pattern
+void
+NumberFormatTest::TestExponential(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormatSymbols ct"); return; }
+ const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
+ int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
+
+// The following #if statements allow this test to be built and run on
+// platforms that do not have standard IEEE numerics. For example,
+// S/390 doubles have an exponent range of -78 to +75. For the
+// following #if statements to work, float.h must define
+// DBL_MAX_10_EXP to be a compile-time constant.
+
+// This section may be expanded as needed.
+
+#if DBL_MAX_10_EXP > 300
+ double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
+ int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0]));
+ const char* valFormat[] =
+ {
+ // 0.####E0
+ "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
+ // 00.000E00
+ "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
+ // ##0.######E000
+ "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
+ // 0.###E0;[0.###E0]
+ "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]"
+ };
+ double valParse[] =
+ {
+ 0.01234, 123460000, 1.23E300, -3.1416E-271,
+ 0.01234, 123460000, 1.23E300, -3.1416E-271,
+ 0.01234, 123456800, 1.23E300, -3.141593E-271,
+ 0.01234, 123500000, 1.23E300, -3.142E-271,
+ };
+#elif DBL_MAX_10_EXP > 70
+ double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 };
+ int32_t val_length = sizeof(val) / sizeof(val[0]);
+ char* valFormat[] =
+ {
+ // 0.####E0
+ "1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71",
+ // 00.000E00
+ "12.340E-03", "12.346E07", "12.300E69", "-31.416E-72",
+ // ##0.######E000
+ "12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072",
+ // 0.###E0;[0.###E0]
+ "1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]"
+ };
+ double valParse[] =
+ {
+ 0.01234, 123460000, 1.23E70, -3.1416E-71,
+ 0.01234, 123460000, 1.23E70, -3.1416E-71,
+ 0.01234, 123456800, 1.23E70, -3.141593E-71,
+ 0.01234, 123500000, 1.23E70, -3.142E-71,
+ };
+#else
+ // Don't test double conversion
+ double* val = 0;
+ int32_t val_length = 0;
+ char** valFormat = 0;
+ double* valParse = 0;
+ logln("Warning: Skipping double conversion tests");
+#endif
+
+ int32_t lval[] = { 0, -1, 1, 123456789 };
+ int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0]));
+ const char* lvalFormat[] =
+ {
+ // 0.####E0
+ "0E0", "-1E0", "1E0", "1.2346E8",
+ // 00.000E00
+ "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
+ // ##0.######E000
+ "0E000", "-1E000", "1E000", "123.4568E006",
+ // 0.###E0;[0.###E0]
+ "0E0", "[1E0]", "1E0", "1.235E8"
+ };
+ int32_t lvalParse[] =
+ {
+ 0, -1, 1, 123460000,
+ 0, -1, 1, 123460000,
+ 0, -1, 1, 123456800,
+ 0, -1, 1, 123500000,
+ };
+ int32_t ival = 0, ilval = 0;
+ for (int32_t p=0; p<pat_length; ++p)
+ {
+ DecimalFormat fmt(pat[p], sym, status);
+ if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; }
+ UnicodeString pattern;
+ logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" +
+ fmt.toPattern(pattern) + "\"");
+ int32_t v;
+ for (v=0; v<val_length; ++v)
+ {
+ UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s);
+ logln((UnicodeString)" " + val[v] + " -format-> " + s);
+ if (s != valFormat[v+ival])
+ errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]);
+
+ ParsePosition pos(0);
+ Formattable af;
+ fmt.parse(s, af, pos);
+ double a;
+ UBool useEpsilon = FALSE;
+ if (af.getType() == Formattable::kLong)
+ a = af.getLong();
+ else if (af.getType() == Formattable::kDouble) {
+ a = af.getDouble();
+#if defined(OS390) || defined(OS400)
+ // S/390 will show a failure like this:
+ //| -3.141592652999999e-271 -format-> -3.1416E-271
+ //| -parse-> -3.1416e-271
+ //| FAIL: Expected -3.141599999999999e-271
+ // To compensate, we use an epsilon-based equality
+ // test on S/390 only. We don't want to do this in
+ // general because it's less exacting.
+ useEpsilon = TRUE;
+#endif
+ }
+ else {
+ errln((UnicodeString)"FAIL: Non-numeric Formattable returned");
+ continue;
+ }
+ if (pos.getIndex() == s.length())
+ {
+ logln((UnicodeString)" -parse-> " + a);
+ // Use epsilon comparison as necessary
+ if ((useEpsilon &&
+ (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
+ (!useEpsilon && a != valParse[v+ival]))
+ {
+ errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]);
+ }
+ }
+ else {
+ errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
+ errln((UnicodeString)" should be (" + s.length() + " chars) -> " + valParse[v+ival]);
+ }
+ }
+ for (v=0; v<lval_length; ++v)
+ {
+ UnicodeString s;
+ (*(NumberFormat*)&fmt).format(lval[v], s);
+ logln((UnicodeString)" " + lval[v] + "L -format-> " + s);
+ if (s != lvalFormat[v+ilval])
+ errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s);
+
+ ParsePosition pos(0);
+ Formattable af;
+ fmt.parse(s, af, pos);
+ if (af.getType() == Formattable::kLong ||
+ af.getType() == Formattable::kInt64) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t a = af.getLong(status);
+ if (pos.getIndex() == s.length())
+ {
+ logln((UnicodeString)" -parse-> " + a);
+ if (a != lvalParse[v+ilval])
+ errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]);
+ }
+ else
+ errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
+ }
+ else
+ errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s
+ + " Double: " + af.getDouble()
+ + ", Long: " + af.getLong());
+ }
+ ival += val_length;
+ ilval += lval_length;
+ }
+}
+
+void
+NumberFormatTest::TestScientific2() {
+ // jb 2552
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
+ if (U_SUCCESS(status)) {
+ double num = 12.34;
+ expect(*fmt, num, "$12.34");
+ fmt->setScientificNotation(TRUE);
+ expect(*fmt, num, "$1.23E1");
+ fmt->setScientificNotation(FALSE);
+ expect(*fmt, num, "$12.34");
+ }
+ delete fmt;
+}
+
+void
+NumberFormatTest::TestScientificGrouping() {
+ // jb 2552
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat fmt("##0.00E0",status);
+ if (U_SUCCESS(status)) {
+ expect(fmt, .01234, "12.3E-3");
+ expect(fmt, .1234, "123E-3");
+ expect(fmt, 1.234, "1.23E0");
+ expect(fmt, 12.34, "12.3E0");
+ expect(fmt, 123.4, "123E0");
+ expect(fmt, 1234., "1.23E3");
+ }
+}
+
+/*static void setFromString(DigitList& dl, const char* str) {
+ char c;
+ UBool decimalSet = FALSE;
+ dl.clear();
+ while ((c = *str++)) {
+ if (c == '-') {
+ dl.fIsPositive = FALSE;
+ } else if (c == '+') {
+ dl.fIsPositive = TRUE;
+ } else if (c == '.') {
+ dl.fDecimalAt = dl.fCount;
+ decimalSet = TRUE;
+ } else {
+ dl.append(c);
+ }
+ }
+ if (!decimalSet) {
+ dl.fDecimalAt = dl.fCount;
+ }
+}*/
+
+void
+NumberFormatTest::TestInt64() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat fmt("#.#E0",status);
+ fmt.setMaximumFractionDigits(20);
+ if (U_SUCCESS(status)) {
+ expect(fmt, (Formattable)(int64_t)0, "0E0");
+ expect(fmt, (Formattable)(int64_t)-1, "-1E0");
+ expect(fmt, (Formattable)(int64_t)1, "1E0");
+ expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9");
+ expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9");
+ expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18");
+ expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18");
+ }
+
+ // also test digitlist
+/* int64_t int64max = U_INT64_MAX;
+ int64_t int64min = U_INT64_MIN;
+ const char* int64maxstr = "9223372036854775807";
+ const char* int64minstr = "-9223372036854775808";
+ UnicodeString fail("fail: ");
+
+ // test max int64 value
+ DigitList dl;
+ setFromString(dl, int64maxstr);
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + int64maxstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != int64max) {
+ errln(fail + int64maxstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != int64max) {
+ errln(fail + int64maxstr);
+ }
+ }
+ // test negative of max int64 value (1 shy of min int64 value)
+ dl.fIsPositive = FALSE;
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-" + int64maxstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != -int64max) {
+ errln(fail + "-" + int64maxstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != -int64max) {
+ errln(fail + "-" + int64maxstr);
+ }
+ }
+ // test min int64 value
+ setFromString(dl, int64minstr);
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-" + int64minstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != int64min) {
+ errln(fail + int64minstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != int64min) {
+ errln(fail + int64minstr);
+ }
+ }
+ // test negative of min int 64 value (1 more than max int64 value)
+ dl.fIsPositive = TRUE; // won't fit
+ {
+ if (dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-(" + int64minstr + ") didn't fit");
+ }
+ }*/
+}
+
+// -------------------------------------
+
+// Test the handling of quotes
+void
+NumberFormatTest::TestQuotes(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString *pat;
+ DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status);
+ pat = new UnicodeString("a'fo''o'b#");
+ DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status);
+ UnicodeString s;
+ ((NumberFormat*)fmt)->format((int32_t)123, s);
+ logln((UnicodeString)"Pattern \"" + *pat + "\"");
+ logln((UnicodeString)" Format 123 -> " + escape(s));
+ if (!(s=="afo'ob123"))
+ errln((UnicodeString)"FAIL: Expected afo'ob123");
+
+ s.truncate(0);
+ delete fmt;
+ delete pat;
+
+ pat = new UnicodeString("a''b#");
+ fmt = new DecimalFormat(*pat, *sym, status);
+ ((NumberFormat*)fmt)->format((int32_t)123, s);
+ logln((UnicodeString)"Pattern \"" + *pat + "\"");
+ logln((UnicodeString)" Format 123 -> " + escape(s));
+ if (!(s=="a'b123"))
+ errln((UnicodeString)"FAIL: Expected a'b123");
+ delete fmt;
+ delete pat;
+ delete sym;
+}
+
+/**
+ * Test the handling of the currency symbol in patterns.
+ */
+void
+NumberFormatTest::TestCurrencySign(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status);
+ UnicodeString pat;
+ UChar currency = 0x00A4;
+ // "\xA4#,##0.00;-\xA4#,##0.00"
+ pat.append(currency).append("#,##0.00;-").
+ append(currency).append("#,##0.00");
+ DecimalFormat *fmt = new DecimalFormat(pat, *sym, status);
+ UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s);
+ pat.truncate(0);
+ logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
+ logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
+ if (s != "$1,234.56") errln((UnicodeString)"FAIL: Expected $1,234.56");
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(- 1234.56, s);
+ logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
+ if (s != "-$1,234.56") errln((UnicodeString)"FAIL: Expected -$1,234.56");
+ delete fmt;
+ pat.truncate(0);
+ // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
+ pat.append(currency).append(currency).
+ append(" #,##0.00;").
+ append(currency).append(currency).
+ append(" -#,##0.00");
+ fmt = new DecimalFormat(pat, *sym, status);
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(1234.56, s);
+ logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
+ logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
+ if (s != "USD 1,234.56") errln((UnicodeString)"FAIL: Expected USD 1,234.56");
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(-1234.56, s);
+ logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
+ if (s != "USD -1,234.56") errln((UnicodeString)"FAIL: Expected USD -1,234.56");
+ delete fmt;
+ delete sym;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+}
+
+// -------------------------------------
+
+static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
+
+UnicodeString&
+NumberFormatTest::escape(UnicodeString& s)
+{
+ UnicodeString buf;
+ for (int32_t i=0; i<s.length(); ++i)
+ {
+ UChar c = s[(int32_t)i];
+ if (c <= (UChar)0x7F) buf += c;
+ else {
+ buf += (UChar)0x5c; buf += (UChar)0x55;
+ buf += toHexString((c & 0xF000) >> 12);
+ buf += toHexString((c & 0x0F00) >> 8);
+ buf += toHexString((c & 0x00F0) >> 4);
+ buf += toHexString(c & 0x000F);
+ }
+ }
+ return (s = buf);
+}
+
+
+// -------------------------------------
+static const char* testCases[][2]= {
+ /* locale ID */ /* expected */
+ {"ca_ES_PREEURO", "1.150 \\u20A7" },
+ {"de_LU_PREEURO", "1,150 F" },
+ {"el_GR_PREEURO", "1.150,50\\u0394\\u03C1\\u03C7" },
+ {"en_BE_PREEURO", "1.150,50 BF" },
+ {"es_ES_PREEURO", "1.150 \\u20A7" },
+ {"eu_ES_PREEURO", "1.150 \\u20A7" },
+ {"gl_ES_PREEURO", "1.150 \\u20A7" },
+ {"it_IT_PREEURO", "\\u20A4 1.150" },
+ {"pt_PT_PREEURO", "1,150$50 Esc."},
+ {"en_US@currency=JPY", "\\u00A51,150"}
+};
+/**
+ * Test localized currency patterns.
+ */
+void
+NumberFormatTest::TestCurrency(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createCurrencyInstance()");
+ return;
+ }
+
+ UnicodeString s; currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre ici a..........." + s);
+ if (!(s=="1,50 $"))
+ errln((UnicodeString)"FAIL: Expected 1,50 $");
+ delete currencyFmt;
+ s.truncate(0);
+ char loc[256]={0};
+ int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status);
+ currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
+ if (!(s=="1,50 DM"))
+ errln((UnicodeString)"FAIL: Expected 1,50 DM");
+ delete currencyFmt;
+ s.truncate(0);
+ len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre en France a....." + s);
+ if (!(s=="1,50 F"))
+ errln((UnicodeString)"FAIL: Expected 1,50 F");
+ delete currencyFmt;
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+
+ for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){
+ status = U_ZERO_ERROR;
+ const char *localeID = testCases[i][0];
+ UnicodeString expected(testCases[i][1]);
+ expected = expected.unescape();
+ s.truncate(0);
+ char loc[256]={0};
+ uloc_canonicalize(localeID, loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ if(U_FAILURE(status)){
+ errln("Could not create currency formatter for locale %s",localeID);
+ continue;
+ }
+ currencyFmt->format(1150.50, s);
+ if(s!=expected){
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
+ }
+ if (U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ }
+ delete currencyFmt;
+ }
+}
+
+// -------------------------------------
+
+/**
+ * Test the Currency object handling, new as of ICU 2.2.
+ */
+void NumberFormatTest::TestCurrencyObject() {
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat* fmt =
+ NumberFormat::createCurrencyInstance(Locale::getUS(), ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getCurrencyInstance(US)");
+ delete fmt;
+ return;
+ }
+
+ Locale null("", "", "");
+
+ expectCurrency(*fmt, null, 1234.56, "$1,234.56");
+
+ expectCurrency(*fmt, Locale::getFrance(),
+ 1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro
+
+ expectCurrency(*fmt, Locale::getJapan(),
+ 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
+
+ expectCurrency(*fmt, Locale("fr", "CH", ""),
+ 1234.56, "SwF1,234.55"); // 0.05 rounding
+
+ expectCurrency(*fmt, Locale::getUS(),
+ 1234.56, "$1,234.56");
+
+ delete fmt;
+ fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getCurrencyInstance(FRANCE)");
+ delete fmt;
+ return;
+ }
+
+ expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC"));
+
+ expectCurrency(*fmt, Locale::getJapan(),
+ 1234.56, CharsToUnicodeString("1 235 \\u00A5JP")); // Yen
+
+ expectCurrency(*fmt, Locale("fr", "CH", ""),
+ 1234.56, "1 234,55 sFr."); // 0.05 rounding
+
+ expectCurrency(*fmt, Locale::getUS(),
+ 1234.56, "1 234,56 $US");
+
+ expectCurrency(*fmt, Locale::getFrance(),
+ 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro
+
+ delete fmt;
+}
+
+// -------------------------------------
+
+/**
+ * Do rudimentary testing of parsing.
+ */
+void
+NumberFormatTest::TestParse(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString arg("0");
+ DecimalFormat* format = new DecimalFormat("00", status);
+ //try {
+ Formattable n; format->parse(arg, n, status);
+ logln((UnicodeString)"parse(" + arg + ") = " + n.getLong());
+ if (n.getType() != Formattable::kLong ||
+ n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
+ delete format;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ //}
+ //catch(Exception e) {
+ // errln((UnicodeString)"Exception caught: " + e);
+ //}
+}
+
+// -------------------------------------
+
+/**
+ * Test proper rounding by the format method.
+ */
+void
+NumberFormatTest::TestRounding487(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createInstance()");
+ return;
+ }
+
+ roundingTest(*nf, 0.00159999, 4, "0.0016");
+ roundingTest(*nf, 0.00995, 4, "0.01");
+
+ roundingTest(*nf, 12.3995, 3, "12.4");
+
+ roundingTest(*nf, 12.4999, 0, "12");
+ roundingTest(*nf, - 19.5, 0, "-20");
+ delete nf;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+}
+
+/**
+ * Test the functioning of the secondary grouping value.
+ */
+void NumberFormatTest::TestSecondaryGrouping(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols ct");
+
+ DecimalFormat f("#,##,###", US, status);
+ CHECK(status, "DecimalFormat ct");
+
+ expect2(f, (int32_t)123456789L, "12,34,56,789");
+ expectPat(f, "#,##,###");
+ f.applyPattern("#,###", status);
+ CHECK(status, "applyPattern");
+
+ f.setSecondaryGroupingSize(4);
+ expect2(f, (int32_t)123456789L, "12,3456,789");
+ expectPat(f, "#,####,###");
+ NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status);
+ CHECK(status, "createInstance(hi_IN)");
+
+ UnicodeString out;
+ int32_t l = (int32_t)1876543210L;
+ g->format(l, out);
+ delete g;
+ // expect "1,87,65,43,210", but with Hindi digits
+ // 01234567890123
+ UBool ok = TRUE;
+ if (out.length() != 14) {
+ ok = FALSE;
+ } else {
+ for (int32_t i=0; i<out.length(); ++i) {
+ UBool expectGroup = FALSE;
+ switch (i) {
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ expectGroup = TRUE;
+ break;
+ }
+ // Later -- fix this to get the actual grouping
+ // character from the resource bundle.
+ UBool isGroup = (out.charAt(i) == 0x002C);
+ if (isGroup != expectGroup) {
+ ok = FALSE;
+ break;
+ }
+ }
+ }
+ if (!ok) {
+ errln((UnicodeString)"FAIL Expected " + l +
+ " x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" +
+ escape(out) + "\"");
+ } else {
+ logln((UnicodeString)"Ok " + l +
+ " x hi_IN -> \"" +
+ escape(out) + "\"");
+ }
+}
+
+void NumberFormatTest::TestWhiteSpaceParsing(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), ec);
+ DecimalFormat fmt("a b#0c ", US, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Constructor");
+ return;
+ }
+ int32_t n = 1234;
+ expect(fmt, "a b1234c ", n);
+ expect(fmt, "a b1234c ", n);
+}
+
+/**
+ * Test currencies whose display name is a ChoiceFormat.
+ */
+void NumberFormatTest::TestComplexCurrency() {
+ UErrorCode ec = U_ZERO_ERROR;
+ Locale loc("en", "IN", "");
+ NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
+ if (U_SUCCESS(ec)) {
+ expect2(*fmt, 1.0, "Re. 1.00");
+ // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
+ expect(*fmt, 1.00390625, "Re. 1.00"); // tricky
+ expect2(*fmt, 12345678.0, "Rs. 1,23,45,678.00");
+ expect2(*fmt, 0.5, "Rs. 0.50");
+ expect2(*fmt, -1.0, "-Re. 1.00");
+ expect2(*fmt, -10.0, "-Rs. 10.00");
+ } else {
+ errln("FAIL: getCurrencyInstance(en_IN)");
+ }
+ delete fmt;
+}
+
+// -------------------------------------
+
+void
+NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected)
+{
+ nf.setMaximumFractionDigits(maxFractionDigits);
+ UnicodeString out; nf.format(x, out);
+ logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out);
+ if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected);
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestExponent(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+ DecimalFormat fmt1(UnicodeString("0.###E0"), US, status);
+ CHECK(status, "DecimalFormat(0.###E0)");
+ DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status);
+ CHECK(status, "DecimalFormat(0.###E+0)");
+ int32_t n = 1234;
+ expect2(fmt1, n, "1.234E3");
+ expect2(fmt2, n, "1.234E+3");
+ expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestScientific(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ // Test pattern round-trip
+ const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000",
+ "0.###E0;[0.###E0]" };
+ int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0]));
+ int32_t DIGITS[] = {
+ // min int, max int, min frac, max frac
+ 0, 1, 0, 0, // "#E0"
+ 1, 1, 0, 4, // "0.####E0"
+ 2, 2, 3, 3, // "00.000E00"
+ 1, 3, 0, 4, // "##0.####E000"
+ 1, 1, 0, 3, // "0.###E0;[0.###E0]"
+ };
+ for (int32_t i=0; i<PAT_length; ++i) {
+ UnicodeString pat(PAT[i]);
+ DecimalFormat df(pat, US, status);
+ CHECK(status, "DecimalFormat constructor");
+ UnicodeString pat2;
+ df.toPattern(pat2);
+ if (pat == pat2) {
+ logln(UnicodeString("Ok Pattern rt \"") +
+ pat + "\" -> \"" +
+ pat2 + "\"");
+ } else {
+ errln(UnicodeString("FAIL Pattern rt \"") +
+ pat + "\" -> \"" +
+ pat2 + "\"");
+ }
+ // Make sure digit counts match what we expect
+ if (df.getMinimumIntegerDigits() != DIGITS[4*i] ||
+ df.getMaximumIntegerDigits() != DIGITS[4*i+1] ||
+ df.getMinimumFractionDigits() != DIGITS[4*i+2] ||
+ df.getMaximumFractionDigits() != DIGITS[4*i+3]) {
+ errln(UnicodeString("FAIL \"" + pat +
+ "\" min/max int; min/max frac = ") +
+ df.getMinimumIntegerDigits() + "/" +
+ df.getMaximumIntegerDigits() + ";" +
+ df.getMinimumFractionDigits() + "/" +
+ df.getMaximumFractionDigits() + ", expect " +
+ DIGITS[4*i] + "/" +
+ DIGITS[4*i+1] + ";" +
+ DIGITS[4*i+2] + "/" +
+ DIGITS[4*i+3]);
+ }
+ }
+
+
+ // Test the constructor for default locale. We have to
+ // manually set the default locale, as there is no
+ // guarantee that the default locale has the same
+ // scientific format.
+ Locale def = Locale::getDefault();
+ Locale::setDefault(Locale::getUS(), status);
+ expect2(NumberFormat::createScientificInstance(status),
+ 12345.678901,
+ "1.2345678901E4", status);
+ Locale::setDefault(def, status);
+
+ expect2(new DecimalFormat("#E0", US, status),
+ 12345.0,
+ "1.2345E4", status);
+ expect(new DecimalFormat("0E0", US, status),
+ 12345.0,
+ "1E4", status);
+ expect2(NumberFormat::createScientificInstance(Locale::getUS(), status),
+ 12345.678901,
+ "1.2345678901E4", status);
+ expect(new DecimalFormat("##0.###E0", US, status),
+ 12345.0,
+ "12.34E3", status);
+ expect(new DecimalFormat("##0.###E0", US, status),
+ 12345.00001,
+ "12.35E3", status);
+ expect2(new DecimalFormat("##0.####E0", US, status),
+ (int32_t) 12345,
+ "12.345E3", status);
+ expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status),
+ 12345.678901,
+ "1,2345678901E4", status);
+ expect(new DecimalFormat("##0.####E0", US, status),
+ 789.12345e-9,
+ "789.12E-9", status);
+ expect2(new DecimalFormat("##0.####E0", US, status),
+ 780.e-9,
+ "780E-9", status);
+ expect(new DecimalFormat(".###E0", US, status),
+ 45678.0,
+ ".457E5", status);
+ expect2(new DecimalFormat(".###E0", US, status),
+ (int32_t) 0,
+ ".0E0", status);
+ /*
+ expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
+ new DecimalFormat("##E0", US),
+ new DecimalFormat("####E0", US),
+ new DecimalFormat("0E0", US),
+ new DecimalFormat("00E0", US),
+ new DecimalFormat("000E0", US),
+ },
+ new Long(45678000),
+ new String[] { "4.5678E7",
+ "45.678E6",
+ "4567.8E4",
+ "5E7",
+ "46E6",
+ "457E5",
+ }
+ );
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("#E0", US, status),
+ (int32_t) 45678000, "4.5678E7", status);
+ expect2(new DecimalFormat("##E0", US, status),
+ (int32_t) 45678000, "45.678E6", status);
+ expect2(new DecimalFormat("####E0", US, status),
+ (int32_t) 45678000, "4567.8E4", status);
+ expect(new DecimalFormat("0E0", US, status),
+ (int32_t) 45678000, "5E7", status);
+ expect(new DecimalFormat("00E0", US, status),
+ (int32_t) 45678000, "46E6", status);
+ expect(new DecimalFormat("000E0", US, status),
+ (int32_t) 45678000, "457E5", status);
+ /*
+ expect(new DecimalFormat("###E0", US, status),
+ new Object[] { new Double(0.0000123), "12.3E-6",
+ new Double(0.000123), "123E-6",
+ new Double(0.00123), "1.23E-3",
+ new Double(0.0123), "12.3E-3",
+ new Double(0.123), "123E-3",
+ new Double(1.23), "1.23E0",
+ new Double(12.3), "12.3E0",
+ new Double(123), "123E0",
+ new Double(1230), "1.23E3",
+ });
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.0000123, "12.3E-6", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.000123, "123E-6", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.00123, "1.23E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.0123, "12.3E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.123, "123E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 1.23, "1.23E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 12.3, "12.3E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 123.0, "123E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 1230.0, "1.23E3", status);
+ /*
+ expect(new DecimalFormat("0.#E+00", US, status),
+ new Object[] { new Double(0.00012), "1.2E-04",
+ new Long(12000), "1.2E+04",
+ });
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("0.#E+00", US, status),
+ 0.00012, "1.2E-04", status);
+ expect2(new DecimalFormat("0.#E+00", US, status),
+ (int32_t) 12000, "1.2E+04", status);
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestPad(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ expect2(new DecimalFormat("*^##.##", US, status),
+ int32_t(0), "^^^^0", status);
+ expect2(new DecimalFormat("*^##.##", US, status),
+ -1.3, "^-1.3", status);
+ expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
+ int32_t(0), "0.0E0______ g-m/s^2", status);
+ expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
+ 1.0/3, "333.333E-3_ g-m/s^2", status);
+ expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
+ int32_t(0), "0.0______ g-m/s^2", status);
+ expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
+ 1.0/3, "0.33333__ g-m/s^2", status);
+
+ // Test padding before a sign
+ const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-10), "xxxxxxxxxx(10.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-1000),"xxxxxxx(1,000.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-1000000),"xxx(1,000,000.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -100.37, "xxxxxxxx(100.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -10456.37, "xxxxx(10,456.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -1120456.37, "xx(1,120,456.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -112045600.37, "(112,045,600.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -1252045600.37,"(1,252,045,600.37)", status);
+
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(10), "xxxxxxxxxxxx10.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(1000),"xxxxxxxxx1,000.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(1000000),"xxxxx1,000,000.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 100.37, "xxxxxxxxxx100.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 10456.37, "xxxxxxx10,456.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 1120456.37, "xxxx1,120,456.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 112045600.37, "xx112,045,600.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 10252045600.37,"10,252,045,600.37", status);
+
+
+ // Test padding between a sign and a number
+ const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-10), "(10.0xxxxxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-1000),"(1,000.0xxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-1000000),"(1,000,000.0xxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -100.37, "(100.37xxxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -10456.37, "(10,456.37xxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -1120456.37, "(1,120,456.37xx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -112045600.37, "(112,045,600.37)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -1252045600.37,"(1,252,045,600.37)", status);
+
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(10), "10.0xxxxxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(1000),"1,000.0xxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(1000000),"1,000,000.0xxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 100.37, "100.37xxxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 10456.37, "10,456.37xxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 1120456.37, "1,120,456.37xxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 112045600.37, "112,045,600.37xx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 10252045600.37,"10,252,045,600.37", status);
+
+ //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
+ DecimalFormat fmt("#", US, status);
+ CHECK(status, "DecimalFormat constructor");
+ UnicodeString padString("P");
+ fmt.setPadCharacter(padString);
+ expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString);
+ fmt.setPadCharacter((UnicodeString)"^");
+ expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^");
+ //commented untill implementation is complete
+ /* fmt.setPadCharacter((UnicodeString)"^^^");
+ expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^");
+ padString.remove();
+ padString.append((UChar)0x0061);
+ padString.append((UChar)0x0302);
+ fmt.setPadCharacter(padString);
+ UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
+ UnicodeString pattern(patternChars);
+ expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString);
+ */
+
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestPatterns2(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ DecimalFormat fmt("#", US, status);
+ CHECK(status, "DecimalFormat constructor");
+
+ UChar hat = 0x005E; /*^*/
+
+ expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
+ expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat);
+ expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat);
+ expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat);
+ expectPad(fmt, "$*^$#", ILLEGAL);
+ expectPad(fmt, "#$*^$", ILLEGAL);
+ expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix,
+ 12, (UChar)0x0078 /*x*/);
+ expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix,
+ 3, (UChar)0x0078 /*x*/);
+ expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix,
+ 10, (UChar)0x0061 /*a*/);
+
+ fmt.applyPattern("AA#,##0.00ZZ", status);
+ CHECK(status, "applyPattern");
+ fmt.setPadCharacter(hat);
+
+ fmt.setFormatWidth(10);
+
+ fmt.setPadPosition(DecimalFormat::kPadBeforePrefix);
+ expectPat(fmt, "*^AA#,##0.00ZZ");
+
+ fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix);
+ expectPat(fmt, "AA#,##0.00*^ZZ");
+
+ fmt.setPadPosition(DecimalFormat::kPadAfterSuffix);
+ expectPat(fmt, "AA#,##0.00ZZ*^");
+
+ // 12 3456789012
+ UnicodeString exp("AA*^#,##0.00ZZ", "");
+ fmt.setFormatWidth(12);
+ fmt.setPadPosition(DecimalFormat::kPadAfterPrefix);
+ expectPat(fmt, exp);
+
+ fmt.setFormatWidth(13);
+ // 12 34567890123
+ expectPat(fmt, "AA*^##,##0.00ZZ");
+
+ fmt.setFormatWidth(14);
+ // 12 345678901234
+ expectPat(fmt, "AA*^###,##0.00ZZ");
+
+ fmt.setFormatWidth(15);
+ // 12 3456789012345
+ expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
+
+ fmt.setFormatWidth(16);
+ // 12 34567890123456
+ expectPat(fmt, "AA*^#,###,##0.00ZZ");
+}
+
+void NumberFormatTest::TestSurrogateSupport(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols custom(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal");
+ custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus");
+ custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus ");
+ custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent");
+
+ UnicodeString patternStr("*\\U00010000##.##", "");
+ patternStr = patternStr.unescape();
+ UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", "");
+ expStr = expStr.unescape();
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(0), expStr, status);
+
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("*^##.##", custom, status),
+ int32_t(0), "^^^^0", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##.##", custom, status),
+ -1.3, " minus 1decimal3", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
+ int32_t(0), "0decimal0exponent0 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
+ 1.0/3, "333decimal333exponent minus 3 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
+ int32_t(0), "0decimal0 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
+ 1.0/3, "0decimal33333 g-m/s^2", status);
+
+ UnicodeString zero((UChar32)0x10000);
+ custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
+ expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", "");
+ expStr = expStr.unescape();
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.000", custom, status),
+ 1.25, expStr, status);
+
+ custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
+ custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
+ custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
+ patternStr = "0.00 \\u00A4' in your bank account'";
+ patternStr = patternStr.unescape();
+ expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", "");
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(-20), expStr, status);
+
+ custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent");
+ patternStr = "'You''ve lost ' -0.00 %' of your money today'";
+ patternStr = patternStr.unescape();
+ expStr = UnicodeString(" minus You've lost minus 2000decimal00 percent of your money today", "");
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(-20), expStr, status);
+}
+
+void NumberFormatTest::TestCurrencyPatterns(void) {
+ int32_t i, locCount;
+ const Locale* locs = NumberFormat::getAvailableLocales(locCount);
+ for (i=0; i<locCount; ++i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec));
+ } else {
+ // Make sure currency formats do not have a variable number
+ // of fraction digits
+ int32_t min = nf->getMinimumFractionDigits();
+ int32_t max = nf->getMaximumFractionDigits();
+ if (min != max) {
+ UnicodeString a, b;
+ nf->format(1.0, a);
+ nf->format(1.125, b);
+ errln((UnicodeString)"FAIL: " + locs[i].getName() +
+ " min fraction digits != max fraction digits; "
+ "x 1.0 => " + escape(a) +
+ "; x 1.125 => " + escape(b));
+ }
+
+ // Make sure EURO currency formats have exactly 2 fraction digits
+ if (nf->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ DecimalFormat* df = (DecimalFormat*) nf;
+ if (u_strcmp(EUR, df->getCurrency()) == 0) {
+ if (min != 2 || max != 2) {
+ UnicodeString a;
+ nf->format(1.0, a);
+ errln((UnicodeString)"FAIL: " + locs[i].getName() +
+ " is a EURO format but it does not have 2 fraction digits; "
+ "x 1.0 => " +
+ escape(a));
+ }
+ }
+ }
+ }
+ delete nf;
+ }
+}
+
+void NumberFormatTest::TestRegCurrency(void) {
+#if !UCONFIG_NO_SERVICE
+ UErrorCode status = U_ZERO_ERROR;
+ UChar USD[4];
+ ucurr_forLocale("en_US", USD, 4, &status);
+ UChar YEN[4];
+ ucurr_forLocale("ja_JP", YEN, 4, &status);
+ UChar TMP[4];
+ static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
+ if(U_FAILURE(status)) {
+ errln("Unable to get currency for locale, error %s", u_errorName(status));
+ return;
+ }
+
+ UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status);
+ UCurrRegistryKey enUSEUROkey = ucurr_register(QQQ, "en_US_EURO", &status);
+
+ ucurr_forLocale("en_US", TMP, 4, &status);
+ if (u_strcmp(YEN, TMP) != 0) {
+ errln("FAIL: didn't return YEN registered for en_US");
+ }
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(QQQ, TMP) != 0) {
+ errln("FAIL: didn't return QQQ for en_US_EURO");
+ }
+
+ int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status);
+ if (fallbackLen) {
+ errln("FAIL: tried to fallback en_XX_BAR");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ if (!ucurr_unregister(enkey, &status)) {
+ errln("FAIL: couldn't unregister enkey");
+ }
+
+ ucurr_forLocale("en_US", TMP, 4, &status);
+ if (u_strcmp(USD, TMP) != 0) {
+ errln("FAIL: didn't return USD for en_US after unregister of en_US");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(QQQ, TMP) != 0) {
+ errln("FAIL: didn't return QQQ for en_US_EURO after unregister of en_US");
+ }
+
+ ucurr_forLocale("en_US_BLAH", TMP, 4, &status);
+ if (u_strcmp(USD, TMP) != 0) {
+ errln("FAIL: could not find USD for en_US_BLAH after unregister of en");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ if (!ucurr_unregister(enUSEUROkey, &status)) {
+ errln("FAIL: couldn't unregister enUSEUROkey");
+ }
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(EUR, TMP) != 0) {
+ errln("FAIL: didn't return EUR for en_US_EURO after unregister of en_US_EURO");
+ }
+ status = U_ZERO_ERROR; // reset
+#endif
+}
+
+void NumberFormatTest::TestCurrencyNames(void) {
+ // Do a basic check of getName()
+ // USD { "US$", "US Dollar" } // 04/04/1792-
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/
+ static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/
+ static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/
+ static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/
+ UBool isChoiceFormat;
+ int32_t len;
+ // Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK
+ // THE LOCALE DATA before diving into the code.
+ assertEquals("USD.getName(SYMBOL_NAME)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(USD, "en",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USD.getName(LONG_NAME)",
+ UnicodeString("US Dollar"),
+ UnicodeString(ucurr_getName(USD, "en",
+ UCURR_LONG_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("Can$"),
+ UnicodeString(ucurr_getName(CAD, "en",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(CAD, "en_CA",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USD.getName(SYMBOL_NAME)",
+ UnicodeString("US$"),
+ UnicodeString(ucurr_getName(USD, "en_AU",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("Can$"),
+ UnicodeString(ucurr_getName(CAD, "en_AU",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USX.getName(LONG_NAME)",
+ UnicodeString("USX"),
+ UnicodeString(ucurr_getName(USX, "en_US",
+ UCURR_LONG_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertSuccess("ucurr_getName", ec);
+
+ ec = U_ZERO_ERROR;
+
+ // Test that a default or fallback warning is being returned. JB 4239.
+ ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "vi", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ // Test that a default warning is being returned when falling back to root. JB 4536.
+ ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default to root)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ // TODO add more tests later
+}
+
+void NumberFormatTest::TestCurrencyUnit(void){
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ CurrencyUnit cu(USD, ec);
+ assertSuccess("CurrencyUnit", ec);
+
+ const UChar * r = cu.getISOCurrency(); // who is the buffer owner ?
+ assertEquals("getISOCurrency()", USD, r);
+
+ CurrencyUnit cu2(cu);
+ if (!(cu2 == cu)){
+ errln("CurrencyUnit copy constructed object should be same");
+ }
+
+ CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone();
+ if (!(*cu3 == cu)){
+ errln("CurrencyUnit cloned object should be same");
+ }
+ delete cu3;
+}
+
+void NumberFormatTest::TestCurrencyAmount(void){
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ CurrencyAmount ca(9, USD, ec);
+ assertSuccess("CurrencyAmount", ec);
+
+ CurrencyAmount ca2(ca);
+ if (!(ca2 == ca)){
+ errln("CurrencyAmount copy constructed object should be same");
+ }
+
+ ca2=ca;
+ if (!(ca2 == ca)){
+ errln("CurrencyAmount assigned object should be same");
+ }
+
+ CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone();
+ if (!(*ca3 == ca)){
+ errln("CurrencyAmount cloned object should be same");
+ }
+ delete ca3;
+}
+
+void NumberFormatTest::TestSymbolsWithBadLocale(void) {
+ Locale locDefault;
+ Locale locBad("x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME");
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString intlCurrencySymbol((UChar)0xa4);
+
+ intlCurrencySymbol.append((UChar)0xa4);
+
+ logln("Current locale is %s", Locale::getDefault().getName());
+ Locale::setDefault(locBad, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
+ DecimalFormatSymbols mySymbols(status);
+ if (status != U_USING_FALLBACK_WARNING) {
+ errln("DecimalFormatSymbols should returned U_USING_FALLBACK_WARNING.");
+ }
+ if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
+ errln("DecimalFormatSymbols does not have the right locale.");
+ }
+ int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
+ for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
+ logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ")
+ + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum)));
+
+ if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0
+ && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
+ && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
+ {
+ errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
+ }
+ }
+ status = U_ZERO_ERROR;
+ Locale::setDefault(locDefault, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
+}
+
+/**
+ * Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols
+ * behave the same, except for memory ownership semantics. (No
+ * version of this test on Java, since Java has only one method.)
+ */
+void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ UnicodeString pat(" #,##0.00");
+ pat.insert(0, (UChar)0x00A4);
+ DecimalFormat fmt(pat, sym, ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormat constructor");
+ return;
+ }
+
+ UnicodeString str;
+ fmt.format(2350.75, str);
+ if (str == "$ 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: " + str + ", expected $ 2,350.75");
+ }
+
+ sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
+ fmt.adoptDecimalFormatSymbols(sym);
+
+ str.truncate(0);
+ fmt.format(2350.75, str);
+ if (str == "Q 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ }
+
+ sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ DecimalFormat fmt2(pat, sym, ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormat constructor");
+ return;
+ }
+
+ DecimalFormatSymbols sym2(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ return;
+ }
+ sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
+ fmt2.setDecimalFormatSymbols(sym2);
+
+ str.truncate(0);
+ fmt2.format(2350.75, str);
+ if (str == "Q 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ }
+}
+
+void NumberFormatTest::TestPerMill() {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString str;
+ DecimalFormat fmt(ctou("###.###\\u2030"), ec);
+ if (!assertSuccess("DecimalFormat ct", ec)) return;
+ assertEquals("0.4857 x ###.###\\u2030",
+ ctou("485.7\\u2030"), fmt.format(0.4857, str));
+
+ DecimalFormatSymbols sym(Locale::getUS(), ec);
+ sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
+ DecimalFormat fmt2("", sym, ec);
+ fmt2.applyLocalizedPattern("###.###m", ec);
+ if (!assertSuccess("setup", ec)) return;
+ str.truncate(0);
+ assertEquals("0.4857 x ###.###m",
+ "485.7m", fmt2.format(0.4857, str));
+}
+
+/**
+ * Generic test for patterns that should be legal/illegal.
+ */
+void NumberFormatTest::TestIllegalPatterns() {
+ // Test cases:
+ // Prefix with "-:" for illegal patterns
+ // Prefix with "+:" for legal patterns
+ const char* DATA[] = {
+ // Unquoted special characters in the suffix are illegal
+ "-:000.000|###",
+ "+:000.000'|###'",
+ 0
+ };
+ for (int32_t i=0; DATA[i]; ++i) {
+ const char* pat=DATA[i];
+ UBool valid = (*pat) == '+';
+ pat += 2;
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormat fmt(pat, ec); // locale doesn't matter here
+ if (U_SUCCESS(ec) == valid) {
+ logln("Ok: pattern \"%s\": %s",
+ pat, u_errorName(ec));
+ } else {
+ errln("FAIL: pattern \"%s\" should have %s; got %s",
+ pat, (valid?"succeeded":"failed"),
+ u_errorName(ec));
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+
+static const char* KEYWORDS[] = {
+ /*0*/ "ref=", // <reference pattern to parse numbers>
+ /*1*/ "loc=", // <locale for formats>
+ /*2*/ "f:", // <pattern or '-'> <number> <exp. string>
+ /*3*/ "fp:", // <pattern or '-'> <number> <exp. string> <exp. number>
+ /*4*/ "rt:", // <pattern or '-'> <(exp.) number> <(exp.) string>
+ /*5*/ "p:", // <pattern or '-'> <string> <exp. number>
+ /*6*/ "perr:", // <pattern or '-'> <invalid string>
+ /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
+ /*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
+ 0
+};
+
+/**
+ * Return an integer representing the next token from this
+ * iterator. The integer will be an index into the given list, or
+ * -1 if there are no more tokens, or -2 if the token is not on
+ * the list.
+ */
+static int32_t keywordIndex(const UnicodeString& tok) {
+ for (int32_t i=0; KEYWORDS[i]!=0; ++i) {
+ if (tok==KEYWORDS[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Parse a CurrencyAmount using the given NumberFormat, with
+ * the 'delim' character separating the number and the currency.
+ */
+static void parseCurrencyAmount(const UnicodeString& str,
+ const NumberFormat& fmt,
+ UChar delim,
+ Formattable& result,
+ UErrorCode& ec) {
+ UnicodeString num, cur;
+ int32_t i = str.indexOf(delim);
+ str.extractBetween(0, i, num);
+ str.extractBetween(i+1, INT32_MAX, cur);
+ Formattable n;
+ fmt.parse(num, n, ec);
+ result.adoptObject(new CurrencyAmount(n, cur.getTerminatedBuffer(), ec));
+}
+
+void NumberFormatTest::TestCases() {
+ UErrorCode ec = U_ZERO_ERROR;
+ TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Couldn't open NumberFormatTestCases.txt");
+ return;
+ }
+ TokenIterator tokens(&reader);
+
+ Locale loc("en", "US", "");
+ DecimalFormat *ref = 0, *fmt = 0;
+ MeasureFormat *mfmt = 0;
+ UnicodeString pat, tok, mloc, str, out, where, currAmt;
+ Formattable n;
+
+ for (;;) {
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) {
+ break;
+ }
+ where = UnicodeString("(") + tokens.getLineNumber() + ") ";
+ int32_t cmd = keywordIndex(tok);
+ switch (cmd) {
+ case 0:
+ // ref= <reference pattern>
+ if (!tokens.next(tok, ec)) goto error;
+ delete ref;
+ ref = new DecimalFormat(tok,
+ new DecimalFormatSymbols(Locale::getUS(), ec), ec);
+ if (U_FAILURE(ec)) {
+ dataerrln("Error constructing DecimalFormat");
+ goto error;
+ }
+ break;
+ case 1:
+ // loc= <locale>
+ if (!tokens.next(tok, ec)) goto error;
+ loc = Locale::createFromName(CharString(tok));
+ break;
+ case 2: // f:
+ case 3: // fp:
+ case 4: // rt:
+ case 5: // p:
+ if (!tokens.next(tok, ec)) goto error;
+ if (tok != "-") {
+ pat = tok;
+ delete fmt;
+ fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec));
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ if (cmd == 3) {
+ if (!tokens.next(tok, ec)) goto error;
+ }
+ continue;
+ }
+ }
+ if (cmd == 2 || cmd == 3 || cmd == 4) {
+ // f: <pattern or '-'> <number> <exp. string>
+ // fp: <pattern or '-'> <number> <exp. string> <exp. number>
+ // rt: <pattern or '-'> <number> <string>
+ UnicodeString num;
+ if (!tokens.next(num, ec)) goto error;
+ if (!tokens.next(str, ec)) goto error;
+ ref->parse(num, n, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".format(" + num + ")",
+ str, fmt->format(n, out.remove(), ec));
+ assertSuccess("format", ec);
+ if (cmd == 3) { // fp:
+ if (!tokens.next(num, ec)) goto error;
+ ref->parse(num, n, ec);
+ assertSuccess("parse", ec);
+ }
+ if (cmd != 2) { // != f:
+ Formattable m;
+ fmt->parse(str, m, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
+ n, m);
+ }
+ }
+ // p: <pattern or '-'> <string to parse> <exp. number>
+ else {
+ UnicodeString expstr;
+ if (!tokens.next(str, ec)) goto error;
+ if (!tokens.next(expstr, ec)) goto error;
+ Formattable exp, n;
+ ref->parse(expstr, exp, ec);
+ assertSuccess("parse", ec);
+ fmt->parse(str, n, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
+ exp, n);
+ }
+ break;
+ case 8: // fpc:
+ if (!tokens.next(tok, ec)) goto error;
+ if (tok != "-") {
+ mloc = tok;
+ delete mfmt;
+ mfmt = MeasureFormat::createCurrencyFormat(
+ Locale::createFromName(CharString(mloc)), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec));
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ continue;
+ }
+ }
+ // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
+ if (!tokens.next(currAmt, ec)) goto error;
+ if (!tokens.next(str, ec)) goto error;
+ parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
+ if (assertSuccess("parseCurrencyAmount", ec)) {
+ assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
+ str, mfmt->format(n, out.remove(), ec));
+ assertSuccess("format", ec);
+ }
+ if (!tokens.next(currAmt, ec)) goto error;
+ parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
+ if (assertSuccess("parseCurrencyAmount", ec)) {
+ Formattable m;
+ mfmt->parseObject(str, m, ec);
+ if (assertSuccess("parseCurrency", ec)) {
+ assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
+ n, m);
+ }
+ }
+ break;
+ case 6:
+ // perr: <pattern or '-'> <invalid string>
+ errln("FAIL: Under construction");
+ goto done;
+ case 7: {
+ // pat: <pattern> <exp. toPattern, or '-' or 'err'>
+ UnicodeString testpat;
+ UnicodeString exppat;
+ if (!tokens.next(testpat, ec)) goto error;
+ if (!tokens.next(exppat, ec)) goto error;
+ UBool err = exppat == "err";
+ UBool existingPat = FALSE;
+ if (testpat == "-") {
+ if (err) {
+ errln("FAIL: " + where + "Invalid command \"pat: - err\"");
+ continue;
+ }
+ existingPat = TRUE;
+ testpat = pat;
+ }
+ if (exppat == "-") exppat = testpat;
+ DecimalFormat* f = 0;
+ UErrorCode ec2 = U_ZERO_ERROR;
+ if (existingPat) {
+ f = fmt;
+ } else {
+ f = new DecimalFormat(testpat, ec2);
+ }
+ if (U_SUCCESS(ec2)) {
+ if (err) {
+ errln("FAIL: " + where + "Invalid pattern \"" + testpat +
+ "\" was accepted");
+ } else {
+ UnicodeString pat2;
+ assertEquals(where + "\"" + testpat + "\".toPattern()",
+ exppat, f->toPattern(pat2));
+ }
+ } else {
+ if (err) {
+ logln("Ok: " + where + "Invalid pattern \"" + testpat +
+ "\" failed: " + u_errorName(ec2));
+ } else {
+ errln("FAIL: " + where + "Valid pattern \"" + testpat +
+ "\" failed: " + u_errorName(ec2));
+ }
+ }
+ if (!existingPat) delete f;
+ } break;
+ case -1:
+ errln("FAIL: " + where + "Unknown command \"" + tok + "\"");
+ goto done;
+ }
+ }
+ goto done;
+
+ error:
+ if (U_SUCCESS(ec)) {
+ errln("FAIL: Unexpected EOF");
+ } else {
+ errln("FAIL: " + where + "Unexpected " + u_errorName(ec));
+ }
+
+ done:
+ delete mfmt;
+ delete fmt;
+ delete ref;
+}
+
+
+//----------------------------------------------------------------------
+// Support methods
+//----------------------------------------------------------------------
+
+UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) {
+ if (a.getType() == b.getType()) {
+ return a == b;
+ }
+
+ if (a.getType() == Formattable::kLong) {
+ if (b.getType() == Formattable::kInt64) {
+ return a.getLong() == b.getLong();
+ } else if (b.getType() == Formattable::kDouble) {
+ return (double) a.getLong() == b.getDouble(); // TODO check use of double instead of long
+ }
+ } else if (a.getType() == Formattable::kDouble) {
+ if (b.getType() == Formattable::kLong) {
+ return a.getDouble() == (double) b.getLong();
+ } else if (b.getType() == Formattable::kInt64) {
+ return a.getDouble() == (double)b.getInt64();
+ }
+ } else if (a.getType() == Formattable::kInt64) {
+ if (b.getType() == Formattable::kLong) {
+ return a.getInt64() == (int64_t)b.getLong();
+ } else if (b.getType() == Formattable::kDouble) {
+ return a.getInt64() == (int64_t)b.getDouble();
+ }
+ }
+ return FALSE;
+}
+
+void NumberFormatTest::expect2(NumberFormat& fmt, const Formattable& n, const UnicodeString& str) {
+ // Don't round-trip format test, since we explicitly do it
+ expect(fmt, n, str, FALSE);
+ expect(fmt, str, n);
+}
+
+void NumberFormatTest::expect2(NumberFormat* fmt, const Formattable& n,
+ const UnicodeString& exp,
+ UErrorCode status) {
+ if (U_FAILURE(status)) {
+ errln("FAIL: NumberFormat constructor");
+ } else {
+ expect2(*fmt, n, exp);
+ }
+ delete fmt;
+}
+
+void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const Formattable& n) {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable num;
+ fmt.parse(str, num, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + str + "\"");
+ return;
+ }
+ UnicodeString pat;
+ ((DecimalFormat*) &fmt)->toPattern(pat);
+ if (equalValue(num, n)) {
+ logln(UnicodeString("Ok \"") + str + "\" x " +
+ pat + " = " +
+ toString(num));
+ } else {
+ errln(UnicodeString("FAIL \"") + str + "\" x " +
+ pat + " = " +
+ toString(num) + ", expected " + toString(n));
+ }
+}
+
+void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n,
+ const UnicodeString& exp, UBool rt) {
+ UnicodeString saw;
+ FieldPosition pos;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt.format(n, saw, pos, status);
+ CHECK(status, "NumberFormat::format");
+ UnicodeString pat;
+ ((DecimalFormat*) &fmt)->toPattern(pat);
+ if (saw == exp) {
+ logln(UnicodeString("Ok ") + toString(n) + " x " +
+ escape(pat) + " = \"" +
+ escape(saw) + "\"");
+ // We should be able to round-trip the formatted string =>
+ // number => string (but not the other way around: number
+ // => string => number2, might have number2 != number):
+ if (rt) {
+ Formattable n2;
+ fmt.parse(exp, n2, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\"");
+ return;
+ }
+ UnicodeString saw2;
+ fmt.format(n2, saw2, pos, status);
+ CHECK(status, "NumberFormat::format");
+ if (saw2 != exp) {
+ errln((UnicodeString)"FAIL \"" + exp + "\" => " + toString(n2) +
+ " => \"" + saw2 + "\"");
+ }
+ }
+ } else {
+ errln(UnicodeString("FAIL ") + toString(n) + " x " +
+ escape(pat) + " = \"" +
+ escape(saw) + "\", expected \"" + exp + "\"");
+ }
+}
+
+void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n,
+ const UnicodeString& exp,
+ UErrorCode status) {
+ if (U_FAILURE(status)) {
+ errln("FAIL: NumberFormat constructor");
+ } else {
+ expect(*fmt, n, exp);
+ }
+ delete fmt;
+}
+
+void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale,
+ double value, const UnicodeString& string) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormat& fmt = * (DecimalFormat*) &nf;
+ const UChar DEFAULT_CURR[] = {45/*-*/,0};
+ UChar curr[4];
+ u_strcpy(curr, DEFAULT_CURR);
+ if (*locale.getLanguage() != 0) {
+ ucurr_forLocale(locale.getName(), curr, 4, &ec);
+ assertSuccess("ucurr_forLocale", ec);
+ fmt.setCurrency(curr, ec);
+ assertSuccess("DecimalFormat::setCurrency", ec);
+ fmt.setCurrency(curr); //Deprecated variant, for coverage only
+ }
+ UnicodeString s;
+ fmt.format(value, s);
+ s.findAndReplace((UChar32)0x00A0, (UChar32)0x0020);
+
+ // Default display of the number yields "1234.5599999999999"
+ // instead of "1234.56". Use a formatter to fix this.
+ NumberFormat* f =
+ NumberFormat::createInstance(Locale::getUS(), ec);
+ UnicodeString v;
+ if (U_FAILURE(ec)) {
+ // Oops; bad formatter. Use default op+= display.
+ v = (UnicodeString)"" + value;
+ } else {
+ f->setMaximumFractionDigits(4);
+ f->setGroupingUsed(FALSE);
+ f->format(value, v);
+ }
+ delete f;
+
+ if (s == string) {
+ logln((UnicodeString)"Ok: " + v + " x " + curr + " => " + prettify(s));
+ } else {
+ errln((UnicodeString)"FAIL: " + v + " x " + curr + " => " + prettify(s) +
+ ", expected " + prettify(string));
+ }
+}
+
+void NumberFormatTest::expectPat(DecimalFormat& fmt, const UnicodeString& exp) {
+ UnicodeString pat;
+ fmt.toPattern(pat);
+ if (pat == exp) {
+ logln(UnicodeString("Ok \"") + pat + "\"");
+ } else {
+ errln(UnicodeString("FAIL \"") + pat + "\", expected \"" + exp + "\"");
+ }
+}
+
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos) {
+ expectPad(fmt, pat, pos, 0, (UnicodeString)"");
+}
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, UChar pad) {
+ expectPad(fmt, pat, pos, width, UnicodeString(pad));
+}
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, const UnicodeString& pad) {
+ int32_t apos = 0, awidth = 0;
+ UnicodeString apadStr;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt.applyPattern(pat, status);
+ if (U_SUCCESS(status)) {
+ apos = fmt.getPadPosition();
+ awidth = fmt.getFormatWidth();
+ apadStr=fmt.getPadCharacterString();
+ } else {
+ apos = -1;
+ awidth = width;
+ apadStr = pad;
+ }
+ if (apos == pos && awidth == width && apadStr == pad) {
+ UnicodeString infoStr;
+ if (pos == ILLEGAL) {
+ infoStr = UnicodeString(" width=", "") + awidth + UnicodeString(" pad=", "") + apadStr;
+ }
+ logln(UnicodeString("Ok \"") + pat + "\" pos=" + apos + infoStr);
+ } else {
+ errln(UnicodeString("FAIL \"") + pat + "\" pos=" + apos +
+ " width=" + awidth + " pad=" + apadStr +
+ ", expected " + pos + " " + width + " " + pad);
+ }
+}
+void NumberFormatTest::TestJB3832(){
+ const char* localeID = "pt_PT@currency=PTE";
+ Locale loc(localeID);
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString expected("1,150$50 Esc.");
+ UnicodeString s;
+ NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status);
+ if(U_FAILURE(status)){
+ errln("Could not create currency formatter for locale %s", localeID);
+ return;
+ }
+ currencyFmt->format(1150.50, s);
+ if(s!=expected){
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
+ }
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ delete currencyFmt;
+}
+
+void NumberFormatTest::TestHost()
+{
+#ifdef U_WINDOWS
+ Win32NumberTest::testLocales(this);
+#endif
+}
+
+void NumberFormatTest::TestHostClone()
+{
+ /*
+ Verify that a cloned formatter gives the same results
+ and is useable after the original has been deleted.
+ */
+ // This is mainly important on Windows.
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("en_US@compat=host");
+ UDate now = Calendar::getNow();
+ NumberFormat *full = NumberFormat::createInstance(loc, status);
+ if (full == NULL || U_FAILURE(status)) {
+ errln("FAIL: Can't create Relative date instance");
+ return;
+ }
+ UnicodeString result1;
+ full->format(now, result1, status);
+ Format *fullClone = full->clone();
+ delete full;
+ full = NULL;
+
+ UnicodeString result2;
+ fullClone->format(now, result2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: format failure.");
+ }
+ if (result1 != result2) {
+ errln("FAIL: Clone returned different result from non-clone.");
+ }
+ delete fullClone;
+}
+
+void NumberFormatTest::TestCurrencyFormat()
+{
+ // This test is here to increase code coverage.
+ UErrorCode status = U_ZERO_ERROR;
+ MeasureFormat *cloneObj;
+ UnicodeString str;
+ Formattable toFormat, result;
+ static const UChar ISO_CODE[4] = {0x0047, 0x0042, 0x0050, 0};
+
+ Locale saveDefaultLocale = Locale::getDefault();
+ Locale::setDefault( Locale::getUK(), status );
+ if (U_FAILURE(status)) {
+ errln("couldn't set default Locale!");
+ return;
+ }
+
+ MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status);
+ Locale::setDefault( saveDefaultLocale, status );
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ return;
+ }
+ cloneObj = (MeasureFormat *)measureObj->clone();
+ if (cloneObj == NULL) {
+ errln("Clone doesn't work");
+ return;
+ }
+ toFormat.adoptObject(new CurrencyAmount(1234.56, ISO_CODE, status));
+ measureObj->format(toFormat, str, status);
+ measureObj->parseObject(str, result, status);
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ if (result != toFormat) {
+ errln("measureObj does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
+ }
+ status = U_ZERO_ERROR;
+ str.truncate(0);
+ cloneObj->format(toFormat, str, status);
+ cloneObj->parseObject(str, result, status);
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ if (result != toFormat) {
+ errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
+ }
+ if (*measureObj != *cloneObj) {
+ errln("Cloned object is not equal to the original object");
+ }
+ delete measureObj;
+ delete cloneObj;
+
+ status = U_USELESS_COLLATOR_ERROR;
+ if (MeasureFormat::createCurrencyFormat(status) != NULL) {
+ errln("createCurrencyFormat should have returned NULL.");
+ }
+}
+
+/* Port of ICU4J rounding test. */
+void NumberFormatTest::TestRounding() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
+
+ if (U_FAILURE(status)) {
+ errln("Unable to create decimal formatter.");
+ return;
+ }
+
+ int roundingIncrements[]={1, 2, 5, 20, 50, 100};
+ int testValues[]={0, 300};
+
+ for (int j=0; j<2; j++) {
+ for (int mode=DecimalFormat::kRoundUp;mode<DecimalFormat::kRoundHalfEven;mode++) {
+ df->setRoundingMode((DecimalFormat::ERoundingMode)mode);
+ for (int increment=0; increment<6; increment++) {
+ double base=testValues[j];
+ double rInc=roundingIncrements[increment];
+ checkRounding(df, base, 20, rInc);
+ rInc=1.000000000/rInc;
+ checkRounding(df, base, 20, rInc);
+ }
+ }
+ }
+
+}
+
+void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) {
+ df->setRoundingIncrement(increment);
+ double lastParsed=INT32_MIN; //Intger.MIN_VALUE
+ for (int i=-iterations; i<=iterations;i++) {
+ double iValue=base+(increment*(i*0.1));
+ double smallIncrement=0.00000001;
+ if (iValue!=0) {
+ smallIncrement*=iValue;
+ }
+ //we not only test the value, but some values in a small range around it
+ lastParsed=checkRound(df, iValue-smallIncrement, lastParsed);
+ lastParsed=checkRound(df, iValue, lastParsed);
+ lastParsed=checkRound(df, iValue+smallIncrement, lastParsed);
+ }
+}
+
+double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) {
+ UErrorCode status=U_ZERO_ERROR;
+ UnicodeString formattedDecimal;
+ double parsed;
+ Formattable result;
+ df->format(iValue, formattedDecimal, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error formatting number.");
+ }
+
+ df->parse(formattedDecimal, result, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error parsing number.");
+ }
+
+ parsed=result.getDouble();
+
+ if (lastParsed>parsed) {
+ errln("Rounding wrong direction! %d > %d", lastParsed, parsed);
+ }
+
+ return lastParsed;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */