diff options
Diffstat (limited to 'Build/source/libs/icu-xetex/test/intltest/numrgts.cpp')
-rw-r--r-- | Build/source/libs/icu-xetex/test/intltest/numrgts.cpp | 2647 |
1 files changed, 2647 insertions, 0 deletions
diff --git a/Build/source/libs/icu-xetex/test/intltest/numrgts.cpp b/Build/source/libs/icu-xetex/test/intltest/numrgts.cpp new file mode 100644 index 00000000000..e93eb5ce1d6 --- /dev/null +++ b/Build/source/libs/icu-xetex/test/intltest/numrgts.cpp @@ -0,0 +1,2647 @@ +/*********************************************************************** + * Copyright (c) 1997-2007, International Business Machines Corporation + * and others. All Rights Reserved. + ***********************************************************************/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "numrgts.h" + +#include <float.h> // DBL_MIN, DBL_MAX +#include <stdio.h> + +#include "unicode/dcfmtsym.h" +#include "unicode/decimfmt.h" +#include "unicode/locid.h" +#include "unicode/resbund.h" +#include "unicode/calendar.h" +#include "unicode/datefmt.h" +#include "unicode/ucurr.h" +#include "putilimp.h" + +class MyNumberFormatTest : public NumberFormat +{ +public: + + virtual UClassID getDynamicClassID(void) const; + + virtual UnicodeString& format( double number, + UnicodeString& toAppendTo, + FieldPosition& pos, + UErrorCode& status) const + { + return NumberFormat::format(number, toAppendTo, pos, status); + } + + /* Just keep this here to make some of the compilers happy */ + virtual UnicodeString& format(const Formattable& obj, + UnicodeString& toAppendTo, + FieldPosition& pos, + UErrorCode& status) const + { + return NumberFormat::format(obj, toAppendTo, pos, status); + } + + /* Just use one of the format functions */ + virtual UnicodeString& format( double /* number */, + UnicodeString& toAppendTo, + FieldPosition& /* pos */) const + { + toAppendTo = ""; + return toAppendTo; + } + + /* + public Number parse(String text, ParsePosition parsePosition) + { return new Integer(0); } + */ + + /* Just use one of the parse functions */ + virtual void parse( const UnicodeString& /* text */, + Formattable& result, + ParsePosition& /* parsePosition */) const + { + result.setLong((int32_t)0); + } + + virtual void parse( const UnicodeString& text, + Formattable& result, + UErrorCode& status) const + { + NumberFormat::parse(text, result, status); + } + virtual Format* clone() const + { return NULL; } + + virtual UnicodeString& format(int32_t, + UnicodeString& foo, + FieldPosition&) const + { return foo.remove(); } + + virtual UnicodeString& format(int64_t, + UnicodeString& foo, + FieldPosition&) const + { return foo.remove(); } + + virtual void applyPattern(const UnicodeString&, UParseError&, UErrorCode&){ + } +}; + +int32_t gMyNumberFormatTestClassID; +UClassID MyNumberFormatTest::getDynamicClassID() const +{ + return (UClassID)&gMyNumberFormatTestClassID; +} + + +// ***************************************************************************** +// class NumberFormatRegressionTest +// ***************************************************************************** + +#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break + +void +NumberFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) +{ + // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest"); + switch (index) { + CASE(0,Test4075713); + CASE(1,Test4074620); + CASE(2,Test4088161); + CASE(3,Test4087245); + CASE(4,Test4087535); + CASE(5,Test4088503); + CASE(6,Test4066646); + CASE(7,Test4059870); + CASE(8,Test4083018); + CASE(9,Test4071492); + CASE(10,Test4086575); + CASE(11,Test4068693); + CASE(12,Test4069754); + CASE(13,Test4087251); + CASE(14,Test4090489); + CASE(15,Test4090504); + CASE(16,Test4095713); + CASE(17,Test4092561); + CASE(18,Test4092480); + CASE(19,Test4087244); + CASE(20,Test4070798); + CASE(21,Test4071005); + CASE(22,Test4071014); + CASE(23,Test4071859); + CASE(24,Test4093610); + CASE(25,Test4098741); + CASE(26,Test4074454); + CASE(27,Test4099404); + CASE(28,Test4101481); + CASE(29,Test4052223); + CASE(30,Test4061302); + CASE(31,Test4062486); + CASE(32,Test4108738); + CASE(33,Test4106658); + CASE(34,Test4106662); + CASE(35,Test4114639); + CASE(36,Test4106664); + CASE(37,Test4106667); + CASE(38,Test4110936); + CASE(39,Test4122840); + CASE(40,Test4125885); + CASE(41,Test4134034); + CASE(42,Test4134300); + CASE(43,Test4140009); + CASE(44,Test4141750); + CASE(45,Test4145457); + CASE(46,Test4147295); + CASE(47,Test4147706); + CASE(48,Test4162198); + CASE(49,Test4162852); + CASE(50,Test4167494); + CASE(51,Test4170798); + CASE(52,Test4176114); + CASE(53,Test4179818); + CASE(54,Test4212072); + CASE(55,Test4216742); + CASE(56,Test4217661); + CASE(57,Test4161100); + CASE(58,Test4243011); + CASE(59,Test4243108); + CASE(60,TestJ691); + + default: name = ""; break; + } +} + +UBool +NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, const Locale& l) +{ + if(U_FAILURE(status)) { + errln(UnicodeString("FAIL: ", "") + msg + + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l.getName(),"")); + return TRUE; + } + + return FALSE; +} + +UBool +NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, const char *l) +{ + if(U_FAILURE(status)) { + errln(UnicodeString("FAIL: ", "") + msg + + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l, "")); + return TRUE; + } + + return FALSE; +} + +UBool +NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg) +{ + if(U_FAILURE(status)) { + errln(UnicodeString("FAIL: ", "") + msg + + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "")); + return TRUE; + } + + return FALSE; +} + +/** + * Convert Java-style strings with \u Unicode escapes into UnicodeString objects + */ +inline UnicodeString str(const char *input) +{ + return CharsToUnicodeString(input); +} + +/* @bug 4075713 + * NumberFormat.equals comparing with null should always return false. + */ +// {sfb} kind of silly in C++, just checking for new success +void NumberFormatRegressionTest::Test4075713(void) +{ + //try { + MyNumberFormatTest *tmp = new MyNumberFormatTest(); + if(tmp != NULL) + logln("NumberFormat.equals passed"); + /*} catch (NullPointerException e) { + errln("(new MyNumberFormatTest()).equals(null) throws unexpected exception"); + }*/ + + delete tmp; +} + +/* @bug 4074620 + * NumberFormat.equals comparing two obj equal even the setGroupingUsed + * flag is different. + */ +void NumberFormatRegressionTest::Test4074620(void) +{ + + MyNumberFormatTest *nf1 = new MyNumberFormatTest(); + MyNumberFormatTest *nf2 = new MyNumberFormatTest(); + + nf1->setGroupingUsed(FALSE); + nf2->setGroupingUsed(TRUE); + + if(nf1 == nf2) + errln("Test for bug 4074620 failed"); + else + logln("Test for bug 4074620 passed."); + + delete nf1; + delete nf2; +} + + +/* @bug 4088161 + * DecimalFormat.format() incorrectly uses maxFractionDigits setting. + */ + +void NumberFormatRegressionTest::Test4088161 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + failure(status, "new DecimalFormat", ""); + double d = 100; + df->setMinimumFractionDigits(0); + df->setMaximumFractionDigits(16); + UnicodeString sBuf1; + FieldPosition fp1(0); + logln(UnicodeString("d = ") + d); + logln("maxFractionDigits = " + df->getMaximumFractionDigits()); + + logln(" format(d) = '" + df->format(d, sBuf1, fp1) + "'"); + df->setMaximumFractionDigits(17); + UnicodeString sBuf2; + FieldPosition fp2(0); + logln("maxFractionDigits = " + df->getMaximumFractionDigits()); + sBuf2 = df->format(d, sBuf2, fp2); + if(sBuf2 != "100") + errln(" format(d) = '" + sBuf2 + "'"); + + delete df; +} + +/* @bug 4087245 + * DecimalFormatSymbols should be cloned in the ctor DecimalFormat. + * DecimalFormat(String, DecimalFormatSymbols). + */ +void NumberFormatRegressionTest::Test4087245 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols *symbols = new DecimalFormatSymbols(status); + failure(status, "new DecimalFormatSymbols", ""); + // {sfb} One note about this test: if you pass in a pointer + // to the symbols, they are adopted and this test will fail, + // even though that is the correct behavior. To test the cloning + // of the symbols, it is necessary to pass in a reference to the symbols + DecimalFormat *df = new DecimalFormat("#,##0.0", *symbols, status); + failure(status, "new DecimalFormat with symbols", ""); + int32_t n = 123; + UnicodeString buf1; + UnicodeString buf2; + FieldPosition pos(FieldPosition::DONT_CARE); + logln(UnicodeString("format(") + n + ") = " + + df->format(n, buf1, pos)); + symbols->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UnicodeString((UChar)0x70)); // change value of field + logln(UnicodeString("format(") + n + ") = " + + df->format(n, buf2, pos)); + if(buf1 != buf2) + errln("Test for bug 4087245 failed"); + + delete df; + delete symbols; +} + +/* @bug 4087535 + * DecimalFormat.format() incorrectly formats 0.0 + */ +void NumberFormatRegressionTest::Test4087535 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + failure(status, "new DecimalFormat", ""); + df->setMinimumIntegerDigits(0); + + double n = 0; + UnicodeString buffer; + FieldPosition pos(FieldPosition::DONT_CARE); + buffer = df->format(n, buffer, pos); + if (buffer.length() == 0) + errln(/*n + */": '" + buffer + "'"); + n = 0.1; + buffer = df->format(n, buffer, pos); + if (buffer.length() == 0) + errln(/*n + */": '" + buffer + "'"); + + delete df; +} + +/* @bug 4088503 + * DecimalFormat.format fails when groupingSize is set to 0. + */ +// {sfb} how do I tell if this worked? --> FieldPosition doesn't change ?? +void NumberFormatRegressionTest::Test4088503 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + failure(status, "new DecimalFormat", ""); + df->setGroupingSize(0); + UnicodeString sBuf; + FieldPosition fp(FieldPosition::DONT_CARE); + //try { + logln(df->format((int32_t)123, sBuf, fp)); + //if(fp == FieldPosition(0)) + // errln("Test for bug 4088503 failed."); + /*} catch (Exception foo) { + errln("Test for bug 4088503 failed."); + }*/ + delete df; + +} +/* @bug 4066646 + * NumberFormat.getCurrencyInstance is wrong. + */ +void NumberFormatRegressionTest::Test4066646 (void) +{ + assignFloatValue(2.04f); + assignFloatValue(2.03f); + assignFloatValue(2.02f); + assignFloatValue(0.0f); +} + +float +NumberFormatRegressionTest::assignFloatValue(float returnfloat) +{ + logln(UnicodeString(" VALUE ") + returnfloat); + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nfcommon = NumberFormat::createCurrencyInstance(Locale::getUS(), status); + if (failure(status, "NumberFormat::createCurrencyInstance", Locale::getUS())){ + delete nfcommon; + return returnfloat; + } + nfcommon->setGroupingUsed(FALSE); + + UnicodeString stringValue; + stringValue = nfcommon->format(returnfloat, stringValue); + logln(" DISPLAYVALUE " + stringValue); + Formattable result; + nfcommon->parse(stringValue, result, status); + failure(status, "nfcommon->parse", Locale::getUS()); + float floatResult = (float) (result.getType() == Formattable::kDouble + ? result.getDouble() : result.getLong()); + if( uprv_fabs(floatResult - returnfloat) > 0.0001) + //String stringValue = nfcommon.format(returnfloat).substring(1); + //if (Float.valueOf(stringValue).floatValue() != returnfloat) + errln(UnicodeString("FAIL: expected ") + returnfloat + ", got " + floatResult + " (" + stringValue+")"); + + delete nfcommon; + return returnfloat; +} // End Of assignFloatValue() + +/* @bug 4059870 + * DecimalFormat throws exception when parsing "0" + */ +void NumberFormatRegressionTest::Test4059870(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *format = new DecimalFormat("00", status); + failure(status, "new Decimalformat", Locale::getUS()); + //try { + Formattable result; + UnicodeString str; + format->parse(UnicodeString("0"), result, status); + failure(status, "format->parse", Locale::getUS()); + + /*} + catch (Exception e) { + errln("Test for bug 4059870 failed : " + e); + }*/ + + delete format; +} +/* @bug 4083018 + * DecimalFormatSymbol.equals should always return false when + * comparing with null. + */ +// {sfb} this is silly in C++ +void NumberFormatRegressionTest::Test4083018 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols *dfs = new DecimalFormatSymbols(status); + failure(status, "new DecimalFormatSymbols", Locale::getUS()); + //try { + if (dfs != NULL) + logln("Test Passed!"); + else + errln("Test for bug 4083018 failed"); + /*} catch (Exception foo) { + errln("Test for bug 4083018 failed => Message : " + foo.getMessage()); + }*/ + + delete dfs; +} + +/* @bug 4071492 + * DecimalFormat does not round up correctly. + */ +void NumberFormatRegressionTest::Test4071492 (void) +{ + double x = 0.00159999; + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf = NumberFormat::createInstance(status); + if (failure(status, "NumberFormat::createInstance", Locale::getUS())) { + delete nf; + return; + } + nf->setMaximumFractionDigits(4); + UnicodeString out; + FieldPosition pos(FieldPosition::DONT_CARE); + out = nf->format(x, out, pos); + logln("0.00159999 formats with 4 fractional digits to " + out); + UnicodeString expected("0.0016"); + if (out != expected) + errln("FAIL: Expected " + expected); + + delete nf; +} + +/* @bug 4086575 + * A space as a group separator for localized pattern causes + * wrong format. WorkAround : use non-breaking space. + */ +void NumberFormatRegressionTest::Test4086575(void) +{ + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf1 = NumberFormat::createInstance(Locale::getFrance(), status); + + // TODO: There is not a good way to find out that the creation of this number format has + // failed. Major rewiring of format construction proposed. + if(U_FAILURE(status)) { + errln("Something is wrong with French number format - it should not fallback. Exitting"); + delete nf1; + return; + } + failure(status, "NumberFormat::createInstance", Locale::getFrance()); + + // C++ workaround to make sure cast works + // Wouldn't dynamic_cast<DecimalFormat*> be great? + if(nf1->getDynamicClassID() != DecimalFormat::getStaticClassID()) { + errln("NumberFormat::createInstance returned incorrect type."); + return; + } + + DecimalFormat *nf = (DecimalFormat*) nf1; + UnicodeString temp; + logln("nf toPattern1: " + nf->toPattern(temp)); + logln("nf toLocPattern1: " + nf->toLocalizedPattern(temp)); + + // No group separator + logln("...applyLocalizedPattern ###,00;(###,00) "); + nf->applyLocalizedPattern(UnicodeString("###,00;(###,00)"), status); + failure(status, "nf->applyLocalizedPattern", Locale::getFrance()); + logln("nf toPattern2: " + nf->toPattern(temp)); + logln("nf toLocPattern2: " + nf->toLocalizedPattern(temp)); + + FieldPosition pos(FieldPosition::DONT_CARE); + logln("nf: " + nf->format((int32_t)1234, temp, pos)); // 1234,00 + logln("nf: " + nf->format((int32_t)-1234, temp, pos)); // (1234,00) + + // Space as group separator + + logln("...applyLocalizedPattern # ###,00;(# ###,00) "); + // nbsp = \u00a0 + //nf->applyLocalizedPattern("#\u00a0###,00;(#\u00a0###,00)"); + UChar patChars[] = { + 0x23, 0x00a0, 0x23, 0x23, 0x23, 0x2c, 0x30, 0x30, 0x3b, + 0x28, 0x23, 0x00a0, 0x23, 0x23, 0x23, 0x2c, 0x30, 0x30, 0x29 + }; + UnicodeString pat(patChars, 19, 19); + nf->applyLocalizedPattern(pat, status); + failure(status, "nf->applyLocalizedPattern", Locale::getFrance()); + logln("nf toPattern2: " + nf->toPattern(temp)); + logln("nf toLocPattern2: " + nf->toLocalizedPattern(temp)); + UnicodeString buffer; + buffer = nf->format((int32_t)1234, buffer, pos); + //if (buffer != UnicodeString("1\u00a0234,00")) + UChar c[] = { + 0x31, 0x00a0, 0x32, 0x33, 0x34, 0x2c, 0x30, 0x30 + }; + UnicodeString cc(c, 8, 8); + if (buffer != cc) + errln("nf : " + buffer); // Expect 1 234,00 + + buffer.remove(); + buffer = nf->format((int32_t)-1234, buffer, pos); + UChar c1[] = { + 0x28, 0x31, 0x00a0, 0x32, 0x33, 0x34, 0x2c, 0x30, 0x30, 0x29 + }; + UnicodeString cc1(c1, 10, 10); + if (buffer != cc1) + errln("nf : " + buffer); // Expect (1 234,00) + + // Erroneously prints: + // 1234,00 , + // (1234,00 ,) + + delete nf1; +} +/* @bug 4068693 + * DecimalFormat.parse returns wrong value + */ +// {sfb} slightly converted into a round-trip test, since in C++ +// there is no Double.toString() +void NumberFormatRegressionTest::Test4068693(void) +{ + logln("----- Test Application -----"); + ParsePosition pos(0); + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + Formattable d; + //Double d = (Double)df.parse("123.55456", pos=new ParsePosition(0)); + df->parse(UnicodeString("123.55456"), d, pos); + //if (!d.toString().equals("123.55456")) { + UnicodeString dstr; + df->setMaximumFractionDigits(999); + df->setMaximumIntegerDigits(999); + FieldPosition fp(FieldPosition::DONT_CARE); + dstr = df->format(d.getDouble(), dstr, fp); + if (dstr != UnicodeString("123.55456")) { + errln(UnicodeString("Result -> ") + d.getDouble()); + } + + delete df; +} + +/* @bug 4069754, 4067878 + * null pointer thrown when accessing a deserialized DecimalFormat + * object. + */ +// {sfb} doesn't apply in C++ +void NumberFormatRegressionTest::Test4069754(void) +{ +/* try { + myformat it = new myformat(); + logln(it.Now()); + FileOutputStream ostream = new FileOutputStream("t.tmp"); + ObjectOutputStream p = new ObjectOutputStream(ostream); + p.writeObject(it); + ostream.close(); + logln("Saved ok."); + + FileInputStream istream = new FileInputStream("t.tmp"); + ObjectInputStream p2 = new ObjectInputStream(istream); + myformat it2 = (myformat)p2.readObject(); + logln(it2.Now()); + istream.close(); + logln("Loaded ok."); + } catch (Exception foo) { + errln("Test for bug 4069754 or 4057878 failed => Exception: " + foo.getMessage()); + } +*/} + +/* @bug 4087251 + * DecimalFormat.applyPattern(String) allows illegal patterns + */ +void NumberFormatRegressionTest::Test4087251 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + //try { + df->applyPattern(UnicodeString("#.#.#"), status); + if( ! U_FAILURE(status)) + errln("df->applyPattern with illegal pattern didn't fail"); + UnicodeString temp; + logln("toPattern() returns \"" + df->toPattern(temp) + "\""); + //errln("applyPattern(\"#.#.#\") doesn't throw IllegalArgumentException"); + /*} catch (IllegalArgumentException e) { + logln("Caught Illegal Argument Error !"); + }*/ + // Second test; added 5/11/98 when reported to fail on 1.2b3 + //try { + df->applyPattern("#0.0#0#0", status); + if( ! U_FAILURE(status)) + errln("df->applyPattern with illegal pattern didn't fail"); + logln("toPattern() returns \"" + df->toPattern(temp) + "\""); + //errln("applyPattern(\"#0.0#0#0\") doesn't throw IllegalArgumentException"); + /*} catch (IllegalArgumentException e) { + logln("Ok - IllegalArgumentException for #0.0#0#0"); + }*/ + + delete df; +} + +/* @bug 4090489 + * DecimalFormat.format() loses precision + */ +void NumberFormatRegressionTest::Test4090489 (void) +{ +// {sfb} sprintf doesn't correctly handle the double, so there is nothing +// that NumberFormat can do. For some reason, it does not format the last 1. + +/* UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + failure(status, "new DecimalFormat"); + df->setMinimumFractionDigits(10); + df->setMaximumFractionDigits(999); + df->setGroupingUsed(FALSE); + double d = 1.000000000000001E7; + //BigDecimal bd = new BigDecimal(d); + UnicodeString sb; + FieldPosition fp(0); + logln(UnicodeString("d = ") + d); + //logln("BigDecimal.toString(): " + bd.toString()); + df->format(d, sb, fp); + if (sb != "10000000.0000000100") { + errln("DecimalFormat.format(): " + sb); + } +*/ +} + +/* @bug 4090504 + * DecimalFormat.format() loses precision + */ +void NumberFormatRegressionTest::Test4090504 (void) +{ + double d = 1; + logln(UnicodeString("d = ") + d); + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + UnicodeString sb; + FieldPosition fp(FieldPosition::DONT_CARE); + //try { + for (int i = 17; i <= 20; i++) { + df->setMaximumFractionDigits(i); + //sb = new StringBuffer(""); + fp.setField(0); + logln(" getMaximumFractionDigits() = " + i); + logln(" formated: " + df->format(d, sb, fp)); + } + /*} catch (Exception foo) { + errln("Bug 4090504 regression test failed. Message : " + foo.getMessage()); + }*/ + + delete df; +} +/* @bug 4095713 + * DecimalFormat.parse(String str, ParsePosition pp) loses precision + */ +void NumberFormatRegressionTest::Test4095713 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + UnicodeString str("0.1234"); + double d1 = 0.1234; + //Double d1 = new Double(str); + //Double d2 = (Double) df.parse(str, new ParsePosition(0)); + Formattable d2; + ParsePosition pp(0); + df->parse(str, d2, pp); + logln(UnicodeString("") + d1); + if (d2.getDouble() != d1) + errln(UnicodeString("Bug 4095713 test failed, new double value : ") + d2.getDouble()); + delete df; +} + +/* @bug 4092561 + * DecimalFormat.parse() fails when multiplier is not set to 1 + */ +// {sfb} not sure what to do with this one +void NumberFormatRegressionTest::Test4092561 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + + // {sfb} going to cheat here and use sprintf ?? + + /*UnicodeString str = Long.toString(Long.MIN_VALUE); + logln("Long.MIN_VALUE : " + df.parse(str, new ParsePosition(0)).toString()); + df.setMultiplier(100); + Number num = df.parse(str, new ParsePosition(0)); + if (num.doubleValue() != -9.223372036854776E16) + errln("Bug 4092561 test failed when multiplier is set to not 1."); +*/ + delete df; +} + +/* @bug 4092480 + * DecimalFormat: Negative format ignored. + */ +void NumberFormatRegressionTest::Test4092480 (void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *dfFoo = new DecimalFormat(UnicodeString("000"), status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete dfFoo; + return; + } + failure(status, "new DecimalFormat"); + + //try { + dfFoo->applyPattern("0000;-000", status); + failure(status, "dfFoo->applyPattern"); + UnicodeString temp; + if (dfFoo->toPattern(temp) != UnicodeString("#0000")) + errln("dfFoo.toPattern : " + dfFoo->toPattern(temp)); + FieldPosition pos(FieldPosition::DONT_CARE); + logln(dfFoo->format((int32_t)42, temp, pos)); + logln(dfFoo->format((int32_t)-42, temp, pos)); + dfFoo->applyPattern("000;-000", status); + failure(status, "dfFoo->applyPattern"); + if (dfFoo->toPattern(temp) != UnicodeString("#000")) + errln("dfFoo.toPattern : " + dfFoo->toPattern(temp)); + logln(dfFoo->format((int32_t)42,temp, pos)); + logln(dfFoo->format((int32_t)-42, temp, pos)); + + dfFoo->applyPattern("000;-0000", status); + failure(status, "dfFoo->applyPattern"); + if (dfFoo->toPattern(temp) != UnicodeString("#000")) + errln("dfFoo.toPattern : " + dfFoo->toPattern(temp)); + logln(dfFoo->format((int32_t)42, temp, pos)); + logln(dfFoo->format((int32_t)-42, temp, pos)); + + dfFoo->applyPattern("0000;-000", status); + failure(status, "dfFoo->applyPattern"); + if (dfFoo->toPattern(temp) != UnicodeString("#0000")) + errln("dfFoo.toPattern : " + dfFoo->toPattern(temp)); + logln(dfFoo->format((int32_t)42, temp, pos)); + logln(dfFoo->format((int32_t)-42, temp, pos)); + /*} catch (Exception foo) { + errln("Message " + foo.getMessage()); + }*/ + + delete dfFoo; +} +/* @bug 4087244 + * NumberFormat.getCurrencyInstance() produces format that uses + * decimal separator instead of monetary decimal separator. + * + * Rewrote this test not to depend on the actual pattern. Pattern should + * never contain the monetary separator! Decimal separator in pattern is + * interpreted as monetary separator if currency symbol is seen! + */ +void NumberFormatRegressionTest::Test4087244 (void) { + UErrorCode status = U_ZERO_ERROR; + char loc[256] = {0}; + uloc_canonicalize("pt_PT_PREEURO", loc, 256, &status); + Locale *de = new Locale(loc); + NumberFormat *nf = NumberFormat::createCurrencyInstance(*de, status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete nf; + return; + } + if (nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) { + errln("expected DecimalFormat!"); + return; + } + DecimalFormat *df = (DecimalFormat*) nf; + const DecimalFormatSymbols *sym = df->getDecimalFormatSymbols(); + UnicodeString decSep = sym->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); + UnicodeString monSep = sym->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); + if (decSep == monSep) { + errln("ERROR in test: want decimal sep != monetary sep"); + return; + } + df->setMinimumIntegerDigits(1); + df->setMinimumFractionDigits(2); + UnicodeString str; + FieldPosition pos; + df->format(1.23, str, pos); + UnicodeString monStr("1x23"); + monStr.replace((int32_t)1, 1, monSep); + UnicodeString decStr("1x23"); + decStr.replace((int32_t)1, 1, decSep); + if (str.indexOf(monStr) >= 0 && str.indexOf(decStr) < 0) { + logln(UnicodeString("OK: 1.23 -> \"") + str + "\" contains \"" + + monStr + "\" and not \"" + decStr + '"'); + } else { + errln(UnicodeString("FAIL: 1.23 -> \"") + str + "\", should contain \"" + + monStr + + "\" and not \"" + decStr + '"'); + } + delete de; + delete nf; +} +/* @bug 4070798 + * Number format data rounding errors for locale FR + */ +void NumberFormatRegressionTest::Test4070798 (void) +{ + NumberFormat *formatter; + UnicodeString tempString; + + /* User error : + String expectedDefault = "-5\u00a0789,987"; + String expectedCurrency = "5\u00a0789,98 F"; + String expectedPercent = "-578\u00a0998%"; + */ + UChar chars1 [] = { + 0x2d, 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x38, 0x38 + }; + UChar chars2 [] = { + 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x39, 0x20, 0x46 + }; + UChar chars3 [] = { + 0x2d, 0x35, 0x37, 0x38, 0x00a0, 0x39, 0x39, 0x39, 0x00a0, 0x25 + }; + UnicodeString expectedDefault(chars1, 10, 10); + UnicodeString expectedCurrency(chars2, 10, 10); + UnicodeString expectedPercent(chars3, 10, 10); + + UErrorCode status = U_ZERO_ERROR; + char loc[256]={0}; + int len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); + formatter = NumberFormat::createInstance(Locale(loc), status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete formatter; + return; + } + failure(status, "NumberFormat::createNumberInstance", loc); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedDefault) { + logln ("Bug 4070798 default test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedDefault + + " Received " + tempString ); + } + delete formatter; + len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); + formatter = NumberFormat::createCurrencyInstance(loc, status); + failure(status, "NumberFormat::createCurrencyInstance", loc); + tempString.remove(); + tempString = formatter->format( 5789.9876, tempString ); + + if (tempString == expectedCurrency) { + logln ("Bug 4070798 currency test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedCurrency + + " Received " + tempString ); + } + delete formatter; + + uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); + formatter = NumberFormat::createPercentInstance(Locale(loc), status); + failure(status, "NumberFormat::createPercentInstance", loc); + tempString.remove(); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedPercent) { + logln ("Bug 4070798 percentage test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedPercent + + " Received " + tempString ); + } + + delete formatter; +} +/* @bug 4071005 + * Data rounding errors for French (Canada) locale + */ +void NumberFormatRegressionTest::Test4071005 (void) +{ + NumberFormat *formatter; + UnicodeString tempString; + /* User error : + String expectedDefault = "-5\u00a0789,987"; + String expectedCurrency = "5\u00a0789,98 $"; + String expectedPercent = "-578\u00a0998%"; + */ + UChar chars1 [] = { + 0x2d, 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x38, 0x38 + }; + UChar chars2 [] = { + 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x39, 0x20, 0x24 + }; + UChar chars3 [] = { + 0x2d, 0x35, 0x37, 0x38, 0x00a0, 0x39, 0x39, 0x39, 0x00a0, 0x25 + }; + UnicodeString expectedDefault(chars1, 10, 10); + UnicodeString expectedCurrency(chars2, 10, 10); + UnicodeString expectedPercent(chars3, 10, 10); + + UErrorCode status = U_ZERO_ERROR; + formatter = NumberFormat::createInstance(Locale::getCanadaFrench(), status); + if (failure(status, "NumberFormat::createNumberInstance", Locale::getCanadaFrench())){ + delete formatter; + return; + }; + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedDefault) { + logln ("Bug 4071005 default test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedDefault + + " Received " + tempString ); + } + delete formatter; + + formatter = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status); + failure(status, "NumberFormat::createCurrencyInstance", Locale::getCanadaFrench()); + tempString.remove(); + tempString = formatter->format( 5789.9876, tempString ); + + if (tempString == expectedCurrency) { + logln ("Bug 4071005 currency test assed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedCurrency + + " Received " + tempString ); + } + delete formatter; + + formatter = NumberFormat::createPercentInstance(Locale::getCanadaFrench(), status); + failure(status, "NumberFormat::createPercentInstance", Locale::getCanadaFrench()); + tempString.remove(); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedPercent) { + logln ("Bug 4071005 percentage test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedPercent + + " Received " + tempString ); + } + + delete formatter; +} + +/* @bug 4071014 + * Data rounding errors for German (Germany) locale + */ +void NumberFormatRegressionTest::Test4071014 (void) +{ + NumberFormat *formatter; + UnicodeString tempString; + /* user error : + String expectedDefault = "-5.789,987"; + String expectedCurrency = "5.789,98 DM"; + String expectedPercent = "-578.998%"; + */ + UnicodeString expectedDefault("-5.789,988"); + UnicodeString expectedCurrency("5.789,99 DM"); + UnicodeString expectedPercent("-578.999 %"); + + UErrorCode status = U_ZERO_ERROR; + char loc[256]={0}; + uloc_canonicalize("de_DE_PREEURO", loc, 256, &status); + formatter = NumberFormat::createInstance(Locale(loc), status); + if (failure(status, "NumberFormat::createNumberInstance", loc)){ + delete formatter; + return; + } + tempString.remove(); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedDefault) { + logln ("Bug 4071014 default test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedDefault + + " Received " + tempString ); + } + delete formatter; + uloc_canonicalize("de_DE_PREEURO", loc, 256, &status); + formatter = NumberFormat::createCurrencyInstance(Locale(loc), status); + failure(status, "NumberFormat::createCurrencyInstance", loc); + tempString.remove(); + tempString = formatter->format( 5789.9876, tempString ); + + if (tempString == expectedCurrency) { + logln ("Bug 4071014 currency test assed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedCurrency + + " Received " + tempString ); + } + delete formatter; + + formatter = NumberFormat::createPercentInstance(Locale::getGermany(), status); + failure(status, "NumberFormat::createPercentInstance", Locale::getGermany()); + tempString.remove(); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedPercent) { + logln ("Bug 4071014 percentage test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedPercent + + " Received " + tempString ); + } + + delete formatter; +} +/* @bug 4071859 + * Data rounding errors for Italian locale number formats + */ +void NumberFormatRegressionTest::Test4071859 (void) +{ + NumberFormat *formatter; + UnicodeString tempString; + /* user error : + String expectedDefault = "-5.789,987"; + String expectedCurrency = "-L. 5.789,98"; + String expectedPercent = "-578.998%"; + */ + UnicodeString expectedDefault("-5.789,988"); + UnicodeString expectedCurrency("-\\u20A4 5.790"); + UnicodeString expectedPercent("-578.999%"); + expectedCurrency = expectedCurrency.unescape(); + + UErrorCode status = U_ZERO_ERROR; + char loc[256]={0}; + uloc_canonicalize("it_IT_PREEURO", loc, 256, &status); + formatter = NumberFormat::createInstance(Locale(loc), status); + if (failure(status, "NumberFormat::createNumberInstance")){ + delete formatter; + return; + }; + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedDefault) { + logln ("Bug 4071859 default test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedDefault + + " Received " + tempString ); + } + delete formatter; + uloc_canonicalize("it_IT_PREEURO", loc, 256, &status); + formatter = NumberFormat::createCurrencyInstance(Locale(loc), status); + failure(status, "NumberFormat::createCurrencyInstance"); + tempString.remove(); + tempString = formatter->format( -5789.9876, tempString ); + + if (tempString == expectedCurrency) { + logln ("Bug 4071859 currency test assed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedCurrency + + " Received " + tempString ); + } + delete formatter; + uloc_canonicalize("it_IT_PREEURO", loc, 256, &status); + formatter = NumberFormat::createPercentInstance(Locale(loc), status); + failure(status, "NumberFormat::createPercentInstance"); + tempString.remove(); + tempString = formatter->format (-5789.9876, tempString); + + if (tempString == expectedPercent) { + logln ("Bug 4071859 percentage test passed."); + } else { + errln(UnicodeString("Failed:") + + " Expected " + expectedPercent + + " Received " + tempString ); + } + + delete formatter; +} +/* @bug 4071859 + * Test rounding for nearest even. + */ +void NumberFormatRegressionTest::Test4093610(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat("#0.#", status); + failure(status, "new DecimalFormat"); + UnicodeString s("12.4"); + roundingTest(df, 12.35, s); + roundingTest(df, 12.45, s); + s = "12.5"; + roundingTest(df, 12.452,s); + s = "12.6"; + roundingTest(df, 12.55, s); + roundingTest(df, 12.65, s); + s = "12.7"; + roundingTest(df, 12.652,s); + s = "12.8"; + roundingTest(df, 12.75, s); + roundingTest(df, 12.752,s); + roundingTest(df, 12.85, s); + s = "12.9"; + roundingTest(df, 12.852,s); + s = "13"; + roundingTest(df, 12.95, s); + roundingTest(df, 12.952,s); + + delete df; +} + +void NumberFormatRegressionTest::roundingTest(DecimalFormat *df, double x, UnicodeString& expected) +{ + UnicodeString out; + FieldPosition pos(FieldPosition::DONT_CARE); + out = df->format(x, out, pos); + logln(UnicodeString("") + x + " formats with 1 fractional digits to " + out); + if (out != expected) + errln("FAIL: Expected " + expected); +} +/* @bug 4098741 + * Tests the setMaximumFractionDigits limit. + */ +void NumberFormatRegressionTest::Test4098741(void) +{ + //try { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *fmt = NumberFormat::createPercentInstance(status); + if (U_FAILURE(status)) { + dataerrln("Error calling NumberFormat::createPercentInstance"); + delete fmt; + return; + } + + fmt->setMaximumFractionDigits(20); + UnicodeString temp; + logln(fmt->format(.001, temp)); + /*} catch (Exception foo) { + errln("Bug 4098471 failed with exception thrown : " + foo.getMessage()); + }*/ + delete fmt; +} +/* @bug 4074454 + * Tests illegal pattern exception. + * Fix comment : HShih A31 Part1 will not be fixed and javadoc needs to be updated. + * Part2 has been fixed. + */ +void NumberFormatRegressionTest::Test4074454(void) +{ + //try { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *fmt = new DecimalFormat("#,#00.00;-#.#", status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete fmt; + return; + } + failure(status, "new DecimalFormat"); + logln("Inconsistent negative pattern is fine."); + DecimalFormat *newFmt = new DecimalFormat("#,#00.00 p''ieces;-#,#00.00 p''ieces", status); + failure(status, "new DecimalFormat"); + UnicodeString tempString; + FieldPosition pos(FieldPosition::DONT_CARE); + tempString = newFmt->format(3456.78, tempString, pos); + if (tempString != UnicodeString("3,456.78 p'ieces")) + errln("Failed! 3456.78 p'ieces expected, but got : " + tempString); + /*} catch (Exception foo) { + errln("An exception was thrown for any inconsistent negative pattern."); + }*/ + + delete fmt; + delete newFmt; +} +/* @bug 4099404 + * Tests all different comments. + * Response to some comments : + * [1] DecimalFormat.parse API documentation is more than just one line. + * This is not a reproducable doc error in 116 source code. + * [2] See updated javadoc. + * [3] Fixed. + * [4] NumberFormat.parse(String, ParsePosition) : If parsing fails, + * a null object will be returned. The unchanged parse position also + * reflects an error. + * NumberFormat.parse(String) : If parsing fails, an ParseException + * will be thrown. + * See updated javadoc for more details. + * [5] See updated javadoc. + * [6] See updated javadoc. + * [7] This is a correct behavior if the DateFormat object is linient. + * Otherwise, an IllegalArgumentException will be thrown when formatting + * "January 35". See GregorianCalendar class javadoc for more details. + */ +void NumberFormatRegressionTest::Test4099404(void) +{ + //try { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *fmt = new DecimalFormat(UnicodeString("000.0#0"), status); + if(! U_FAILURE(status)) + errln(UnicodeString("Bug 4099404 failed applying illegal pattern \"000.0#0\"")); + /*} catch (Exception foo) { + logln("Bug 4099404 pattern \"000.0#0\" passed"); + }*/ + delete fmt; + fmt = 0; + //try { + fmt = new DecimalFormat(UnicodeString("0#0.000"), status); + if( !U_FAILURE(status)) + errln("Bug 4099404 failed applying illegal pattern \"0#0.000\""); + /*} catch (Exception foo) { + logln("Bug 4099404 pattern \"0#0.000\" passed"); + }*/ + + delete fmt; +} +/* @bug 4101481 + * DecimalFormat.applyPattern doesn't set minimum integer digits + */ +void NumberFormatRegressionTest::Test4101481(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *sdf = new DecimalFormat(UnicodeString("#,##0"), status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete sdf; + return; + } + failure(status, "new DecimalFormat"); + if (sdf->getMinimumIntegerDigits() != 1) + errln("Minimum integer digits : " + sdf->getMinimumIntegerDigits()); + delete sdf; +} +/* @bug 4052223 (API addition request A27) + * Tests ParsePosition.setErrorPosition() and ParsePosition.getErrorPosition(). + */ +void NumberFormatRegressionTest::Test4052223(void) +{ + //try { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *fmt = new DecimalFormat(UnicodeString("#,#00.00"), status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete fmt; + return; + } + failure(status, "new DecimalFormat"); + Formattable num; + fmt->parse(UnicodeString("abc3"), num, status); + if(! U_FAILURE(status)) + errln(UnicodeString("Bug 4052223 failed : can't parse string \"a\". Got ") /*+ num*/); + /*} catch (ParseException foo) { + logln("Caught expected ParseException : " + foo.getMessage() + " at index : " + foo.getErrorOffset()); + }*/ + delete fmt; +} +/* @bug 4061302 + * API tests for API addition request A9. + */ +void NumberFormatRegressionTest::Test4061302(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols *fmt = new DecimalFormatSymbols(status); + failure(status, "new DecimalFormatSymbols"); + UnicodeString currency(fmt->getSymbol(DecimalFormatSymbols::kCurrencySymbol)); + UnicodeString intlCurrency(fmt->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); + UnicodeString monDecSeparator(fmt->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol)); + if (currency == UnicodeString("") || + intlCurrency == UnicodeString("") || + monDecSeparator == UnicodeString("")) + { + errln("getCurrencySymbols failed, got empty string."); + } + UnicodeString monDecSeparatorStr; + monDecSeparatorStr.append(monDecSeparator); + logln((UnicodeString)"Before set ==> Currency : " + currency +(UnicodeString)" Intl Currency : " + intlCurrency + (UnicodeString)" Monetary Decimal Separator : " + monDecSeparatorStr); + fmt->setSymbol(DecimalFormatSymbols::kCurrencySymbol, UnicodeString("XYZ")); + fmt->setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, UnicodeString("ABC")); + fmt->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, UnicodeString((UChar)0x002A/*'*'*/)); + currency = fmt->getSymbol(DecimalFormatSymbols::kCurrencySymbol); + intlCurrency = fmt->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); + monDecSeparator = fmt->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); + if (currency != UnicodeString("XYZ") || + intlCurrency != UnicodeString("ABC") || + monDecSeparator != UnicodeString((UChar)0x002A/*'*'*/)) { + errln("setCurrencySymbols failed."); + } + monDecSeparatorStr.remove(); + monDecSeparatorStr.append(monDecSeparator); + logln("After set ==> Currency : " + currency + " Intl Currency : " + intlCurrency + " Monetary Decimal Separator : " + monDecSeparatorStr); + + delete fmt; +} +/* @bug 4062486 + * API tests for API addition request A23. FieldPosition.getBeginIndex and + * FieldPosition.getEndIndex. + */ +void NumberFormatRegressionTest::Test4062486(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *fmt = new DecimalFormat(UnicodeString("#,##0.00"), status); + failure(status, "new DecimalFormat"); + UnicodeString formatted; + FieldPosition field(0); + double num = 1234.5; + fmt->format(num, formatted, field); + if (field.getBeginIndex() != 0 && field.getEndIndex() != 5) + errln(UnicodeString("Format 1234.5 failed. Begin index: ") /*+ field.getBeginIndex() + " End index: " + field.getEndIndex()*/); + field.setBeginIndex(7); + field.setEndIndex(4); + if (field.getBeginIndex() != 7 && field.getEndIndex() != 4) + errln("Set begin/end field indexes failed. Begin index: " /*+ field.getBeginIndex() + " End index: " + field.getEndIndex()*/); + + delete fmt; +} + +/* @bug 4108738 + * DecimalFormat.parse incorrectly works with a group separator. + */ +void NumberFormatRegressionTest::Test4108738(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getUS(), status); + failure(status, "new DecimalFormatSymbols"); + DecimalFormat *df = new DecimalFormat("#,##0.###", syms, status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + UnicodeString text("1.222,111"); + Formattable num; + ParsePosition pp(0); + df->parse(text, num, pp); + + // {sfb} how to do this (again) ? + // shouldn't just be another round-trip test, should it? + UnicodeString temp; + FieldPosition pos(FieldPosition::DONT_CARE); + temp = df->format(num.getDouble(), temp, pos); + //if (!num.toString().equals("1.222")) + if (temp != UnicodeString("1.222")) + //errln("\"" + text + "\" is parsed as " + num); + errln("\"" + text + "\" is parsed as " + temp); + text = UnicodeString("1.222x111"); + pp = ParsePosition(0); + df->parse(text, num, pp); + temp.remove(); + temp = df->format(num.getDouble(), temp, pos); + //if (!num.toString().equals("1.222")) + if (temp != UnicodeString("1.222")) + errln("\"" + text + "\" is parsed as " + temp); + + delete df; +} + +/* @bug 4106658 + * DecimalFormat.format() incorrectly formats negative doubles. + */ +void NumberFormatRegressionTest::Test4106658(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); // Corrected; see 4147706 + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + volatile double d1 = 0.0; // volatile to prevent code optimization + double d2 = -0.0001; + UnicodeString buffer; + UnicodeString temp; + FieldPosition pos(FieldPosition::DONT_CARE); + +#if defined(U_HPUX) + d1 = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword +#else + d1 *= -1.0; // Some compilers have a problem with defining -0.0 +#endif + logln("pattern: \"" + df->toPattern(temp) + "\""); + df->format(d1, buffer, pos); + if (buffer != UnicodeString("-0")) // Corrected; see 4147706 + errln(UnicodeString("") + d1 + " is formatted as " + buffer); + buffer.remove(); + df->format(d2, buffer, pos); + if (buffer != UnicodeString("-0")) // Corrected; see 4147706 + errln(UnicodeString("") + d2 + " is formatted as " + buffer); + + delete df; +} + +/* @bug 4106662 + * DecimalFormat.parse returns 0 if string parameter is incorrect. + */ +void NumberFormatRegressionTest::Test4106662(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + UnicodeString text("x"); + ParsePosition pos1(0), pos2(0); + + UnicodeString temp; + logln("pattern: \"" + df->toPattern(temp) + "\""); + Formattable num; + df->parse(text, num, pos1); + if (pos1 == ParsePosition(0)/*num != null*/) { + errln(UnicodeString("Test Failed: \"") + text + "\" is parsed as " /*+ num*/); + } + delete df; + df = new DecimalFormat(UnicodeString("$###.00"), status); + failure(status, "new DecimalFormat"); + df->parse(UnicodeString("$"), num, pos2); + if (pos2 == ParsePosition(0) /*num != null*/){ + errln(UnicodeString("Test Failed: \"$\" is parsed as ") /*+ num*/); + } + + delete df; +} + +/* @bug 4114639 (duplicate of 4106662) + * NumberFormat.parse doesn't return null + */ +void NumberFormatRegressionTest::Test4114639(void) +{ + UErrorCode status = U_ZERO_ERROR; + NumberFormat *format = NumberFormat::createInstance(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete format; + return; + } + failure(status, "NumberFormat::createInstance"); + UnicodeString text("time 10:x"); + ParsePosition pos(8); + Formattable result; + format->parse(text, result, pos); + if (/*result != null*/pos.getErrorIndex() != 8) + errln(UnicodeString("Should return null but got : ") /*+ result*/); // Should be null; it isn't + + delete format; +} + +/* @bug 4106664 + * TODO: this test does not work because we need to use a 64 bit number and a + * a double only MAY only have 52 bits of precision. + * DecimalFormat.format(long n) fails if n * multiplier > MAX_LONG. + */ +void NumberFormatRegressionTest::Test4106664(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + // {sfb} long in java is 64 bits + /*long*/double n = 1234567890123456.0; + /*int*/int32_t m = 12345678; + // {sfb} will this work? + //BigInteger bigN = BigInteger.valueOf(n); + //bigN = bigN.multiply(BigInteger.valueOf(m)); + double bigN = n * m; + df->setMultiplier(m); + df->setGroupingUsed(FALSE); + UnicodeString temp; + FieldPosition pos(FieldPosition::DONT_CARE); + logln("formated: " + + df->format(n, temp, pos)); + + char buf [128]; + sprintf(buf, "%g", bigN); + //logln("expected: " + bigN.toString()); + logln(UnicodeString("expected: ") + buf); + + delete df; +} +/* @bug 4106667 (duplicate of 4106658) + * DecimalFormat.format incorrectly formats -0.0. + */ +void NumberFormatRegressionTest::Test4106667(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete df; + return; + } + failure(status, "new DecimalFormat"); + UChar foo [] = { 0x002B }; + UnicodeString bar(foo, 1, 1); + volatile double d = 0.0; // volatile to prevent code optimization + UnicodeString temp; + UnicodeString buffer; + FieldPosition pos(FieldPosition::DONT_CARE); + + logln("pattern: \"" + df->toPattern(temp) + "\""); +#if defined(U_HPUX) + d = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword +#else + d *= -1.0; // Some compilers have a problem with defining -0.0 +#endif + df->setPositivePrefix(/*"+"*/bar); + df->format(d, buffer, pos); + if (buffer != UnicodeString("-0")) // Corrected; see 4147706 + errln(/*d + */UnicodeString(" is formatted as ") + buffer); + + delete df; +} + +/* @bug 4110936 + * DecimalFormat.setMaximumIntegerDigits() works incorrectly. + */ +#ifdef OS390 +# define MAX_INT_DIGITS 70 +#else +# define MAX_INT_DIGITS 128 +#endif + +void NumberFormatRegressionTest::Test4110936(void) +{ + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf = NumberFormat::createInstance(status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete nf; + return; + } + failure(status, "NumberFormat::createInstance"); + nf->setMaximumIntegerDigits(MAX_INT_DIGITS); + logln("setMaximumIntegerDigits(MAX_INT_DIGITS)"); + if (nf->getMaximumIntegerDigits() != MAX_INT_DIGITS) + errln("getMaximumIntegerDigits() returns " + + nf->getMaximumIntegerDigits()); + + delete nf; +} + +/* @bug 4122840 + * Locale data should use generic currency symbol + * + * 1) Make sure that all currency formats use the generic currency symbol. + * 2) Make sure we get the same results using the generic symbol or a + * hard-coded one. + */ +void NumberFormatRegressionTest::Test4122840(void) +{ + int32_t count = 0; + const Locale *locales = Locale::getAvailableLocales(count); + + for (int i = 0; i < count; i++) { + UErrorCode status = U_ZERO_ERROR; + ResourceBundle *rb = new ResourceBundle( + NULL/*"java.text.resources.LocaleElements"*/, + locales[i], status); + failure(status, "new ResourceBundle"); + ResourceBundle numPat = rb->get("NumberPatterns", status); + failure(status, "new ResourceBundle(NumberPatterns)"); + // + // Get the currency pattern for this locale. We have to fish it + // out of the ResourceBundle directly, since DecimalFormat.toPattern + // will return the localized symbol, not \00a4 + // + UnicodeString pattern = numPat.getStringEx(1, status); + failure(status, "rb->getStringArray"); + + UChar fo[] = { 0x00A4 }; + UnicodeString foo(fo, 1, 1); + + //if (pattern.indexOf("\u00A4") == -1 ) { + if (pattern.indexOf(foo) == -1 ) { + errln(UnicodeString("Currency format for ") + UnicodeString(locales[i].getName()) + + " does not contain generic currency symbol:" + + pattern ); + } + + // Create a DecimalFormat using the pattern we got and format a number + DecimalFormatSymbols *symbols = new DecimalFormatSymbols(locales[i], status); + failure(status, "new DecimalFormatSymbols"); + DecimalFormat *fmt1 = new DecimalFormat(pattern, *symbols, status); + failure(status, "new DecimalFormat"); + + UnicodeString result1; + FieldPosition pos(FieldPosition::DONT_CARE); + result1 = fmt1->format(1.111, result1, pos); + + // + // Now substitute in the locale's currency symbol and create another + // pattern. We have to skip locales where the currency symbol + // contains decimal separators, because that confuses things + // + UChar ba[] = { 0x002E/*'.'*/ }; + UnicodeString bar(ba, 1, 1); + + if (symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol).indexOf(bar) == -1) { + // {sfb} Also, switch the decimal separator to the monetary decimal + // separator to mimic the behavior of a currency format + symbols->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, + symbols->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol)); + + UnicodeString buf(pattern); + for (int j = 0; j < buf.length(); j++) { + if (buf[j] == 0x00a4 ) { + if(buf[j + 1] == 0x00a4) { + // {sfb} added to support double currency marker (intl currency sign) + buf.replace(j, /*j+*/2, symbols->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); + j += symbols->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol).length(); + } + else { + buf.replace(j, /*j+*/1, symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol)); + j += symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol).length() - 1; + } + } + } + + DecimalFormat *fmt2 = new DecimalFormat(buf, *symbols, status); + failure(status, "new DecimalFormat"); + + // Get the currency (if there is one) so we can set the rounding and fraction + const UChar *currency = fmt1->getCurrency(); + if (*currency != 0) { + double rounding = ucurr_getRoundingIncrement(currency, &status); + int32_t frac = ucurr_getDefaultFractionDigits(currency, &status); + if (U_SUCCESS(status)) { + fmt2->setRoundingIncrement(rounding); + fmt2->setMinimumFractionDigits(frac); + fmt2->setMaximumFractionDigits(frac); + } + else { + failure(status, "Fetching currency rounding/fractions"); + } + } + + UnicodeString result2; + fmt2->format(1.111, result2, pos); + + if (result1 != result2) { + errln("Results for " + (UnicodeString)(locales[i].getName()) + " differ: " + + result1 + " vs " + result2); + } + + delete fmt2; + } + + delete rb; + delete fmt1; + delete symbols; + } +} + +/* @bug 4125885 + * DecimalFormat.format() delivers wrong string. + */ +void NumberFormatRegressionTest::Test4125885(void) +{ + UErrorCode status = U_ZERO_ERROR; + double rate = 12.34; + DecimalFormat *formatDec = new DecimalFormat ("000.00", status); + if(U_FAILURE(status)) { + errln("Error creating DecimalFormat: %s", u_errorName(status)); + delete formatDec; + return; + } + failure(status, "new DecimalFormat"); + UnicodeString temp; + logln("toPattern: " + formatDec->toPattern(temp)); + UnicodeString rateString; + FieldPosition pos(FieldPosition::DONT_CARE); + rateString = formatDec->format(rate, rateString, pos); + if (rateString != UnicodeString("012.34")) + errln("result : " + rateString + " expected : 012.34"); + rate = 0.1234; + delete formatDec;// = null; + formatDec = new DecimalFormat ("+000.00%;-000.00%", status); + failure(status, "new DecimalFormat"); + logln("toPattern: " + formatDec->toPattern(temp)); + rateString.remove(); + rateString = formatDec->format(rate, rateString, pos); + if (rateString != UnicodeString("+012.34%")) + errln("result : " + rateString + " expected : +012.34%"); + + delete formatDec; +} + +/** + * @bug 4134034 + * DecimalFormat produces extra zeros when formatting numbers. + */ +void NumberFormatRegressionTest::Test4134034(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *nf = new DecimalFormat("##,###,###.00", status); + failure(status, "new DecimalFormat"); + + UnicodeString f; + FieldPosition pos(FieldPosition::DONT_CARE); + f = nf->format(9.02, f, pos); + if (f == UnicodeString("9.02")) + logln(f + " ok"); + else + errln("9.02 -> " + f + "; want 9.02"); + + f.remove(); + f = nf->format((int32_t)0, f, pos); + if (f == UnicodeString(".00")) + logln(f + " ok"); + else + errln("0 -> " + f + "; want .00"); + + delete nf; +} + +/** + * @bug 4134300 + * CANNOT REPRODUCE - This bug could not be reproduced. It may be + * a duplicate of 4134034. + * + * JDK 1.1.6 Bug, did NOT occur in 1.1.5 + * Possibly related to bug 4125885. + * + * This class demonstrates a regression in version 1.1.6 + * of DecimalFormat class. + * + * 1.1.6 Results + * Value 1.2 Format #.00 Result '01.20' !!!wrong + * Value 1.2 Format 0.00 Result '001.20' !!!wrong + * Value 1.2 Format 00.00 Result '0001.20' !!!wrong + * Value 1.2 Format #0.0# Result '1.2' + * Value 1.2 Format #0.00 Result '001.20' !!!wrong + * + * 1.1.5 Results + * Value 1.2 Format #.00 Result '1.20' + * Value 1.2 Format 0.00 Result '1.20' + * Value 1.2 Format 00.00 Result '01.20' + * Value 1.2 Format #0.0# Result '1.2' + * Value 1.2 Format #0.00 Result '1.20' + */ +void NumberFormatRegressionTest::Test4134300(void) { + UnicodeString DATA [] = { + // Pattern Expected string + UnicodeString("#.00"), UnicodeString("1.20"), + UnicodeString("0.00"), UnicodeString("1.20"), + UnicodeString("00.00"), UnicodeString("01.20"), + UnicodeString("#0.0#"), UnicodeString("1.2"), + UnicodeString("#0.00"), UnicodeString("1.20") + }; + + for (int i=0; i< 10; i+=2) { + UnicodeString result; + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat(DATA[i], status); + failure(status, "new DecimalFormat"); + FieldPosition pos(FieldPosition::DONT_CARE); + result = df->format(1.2, result, pos); + if (result != DATA[i+1]) { + errln("Fail: 1.2 x " + DATA[i] + " = " + result + + "; want " + DATA[i+1]); + } + else { + logln("Ok: 1.2 x " + DATA[i] + " = " + result); + } + + delete df; + } +} + +/** + * @bug 4140009 + * Empty pattern produces double negative prefix. + */ +void NumberFormatRegressionTest::Test4140009(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getEnglish(), status); + failure(status, "new DecimalFormatSymbols"); + DecimalFormat *f = new DecimalFormat(UnicodeString(""), syms, status); + failure(status, "new DecimalFormat"); + UnicodeString s; + FieldPosition pos(FieldPosition::DONT_CARE); + s = f->format(123.456, s, pos); + if (s != UnicodeString("123.456")) + errln("Fail: Format empty pattern x 123.456 => " + s); + s.remove(); + s = f->format(-123.456, s, pos); + if (s != UnicodeString("-123.456")) + errln("Fail: Format empty pattern x -123.456 => " + s); + delete f; +} + +/** + * @bug 4141750 + * BigDecimal numbers get their fractions truncated by NumberFormat. + */ +// {sfb} not pertinent in C++ ?? +void NumberFormatRegressionTest::Test4141750(void) { + /*try { + UnicodeString str("12345.67"); + BigDecimal bd = new BigDecimal(str); + String sd = NumberFormat.getInstance(Locale.US).format(bd); + if (!sd.endsWith("67")) errln("Fail: " + str + " x format -> " + sd); + } + catch (Exception e) { + errln(e.toString()); + e.printStackTrace(); + }*/ +} + +/** + * @bug 4145457 + * DecimalFormat toPattern() doesn't quote special characters or handle + * single quotes. + */ +void NumberFormatRegressionTest::Test4145457() { + //try { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nff = NumberFormat::createInstance(status); + if (failure(status, "NumberFormat::createInstance")){ + delete nff; + return; + }; + if(nff->getDynamicClassID() != DecimalFormat::getStaticClassID()) { + errln("DecimalFormat needed to continue"); + return; + } + + DecimalFormat *nf = (DecimalFormat*)nff; + DecimalFormatSymbols *sym = (DecimalFormatSymbols*) nf->getDecimalFormatSymbols(); + sym->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, (UChar)/*'\''*/0x0027); + nf->setDecimalFormatSymbols(*sym); + double pi = 3.14159; + + UnicodeString PATS [] = { + UnicodeString("#.00 'num''ber'"), UnicodeString("''#.00''") + }; + + for (int32_t i=0; i<2; ++i) { + nf->applyPattern(PATS[i], status); + failure(status, "nf->applyPattern"); + UnicodeString out; + FieldPosition pos(FieldPosition::DONT_CARE); + out = nf->format(pi, out, pos); + UnicodeString pat; + pat = nf->toPattern(pat); + Formattable num; + ParsePosition pp(0); + nf->parse(out, num, pp); + double val = num.getDouble(); + + nf->applyPattern(pat, status); + failure(status, "nf->applyPattern"); + UnicodeString out2; + out2 = nf->format(pi, out2, pos); + UnicodeString pat2; + pat2 = nf->toPattern(pat2); + nf->parse(out2, num, pp); + double val2 = num.getDouble(); + + if (pat != pat2) + errln("Fail with \"" + PATS[i] + "\": Patterns should concur, \"" + + pat + "\" vs. \"" + pat2 + "\""); + else + logln("Ok \"" + PATS[i] + "\" toPattern() -> \"" + pat + '"'); + + if (val == val2 && out == out2) { + logln(UnicodeString("Ok ") + pi + " x \"" + PATS[i] + "\" -> \"" + + out + "\" -> " + val + " -> \"" + + out2 + "\" -> " + val2); + } + else { + errln(UnicodeString("Fail ") + pi + " x \"" + PATS[i] + "\" -> \"" + + out + "\" -> " + val + " -> \"" + + out2 + "\" -> " + val2); + } + } + /*} + catch (ParseException e) { + errln("Fail: " + e); + e.printStackTrace(); + }*/ + + delete nff; +} + +/** + * @bug 4147295 + * DecimalFormat.applyPattern() sets minimum integer digits incorrectly. + * CANNOT REPRODUCE + * This bug is a duplicate of 4139344, which is a duplicate of 4134300 + */ +void NumberFormatRegressionTest::Test4147295(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *sdf = new DecimalFormat(status); + UnicodeString pattern("#,###"); + logln("Applying pattern \"" + pattern + "\""); + sdf->applyPattern(pattern, status); + failure(status, "sdf->applyPattern"); + int minIntDig = sdf->getMinimumIntegerDigits(); + if (minIntDig != 0) { + errln("Test failed"); + errln(" Minimum integer digits : " + minIntDig); + UnicodeString temp; + errln(" new pattern: " + sdf->toPattern(temp)); + } else { + logln("Test passed"); + logln(" Minimum integer digits : " + minIntDig); + } + delete sdf; +} + +/** + * @bug 4147706 + * DecimalFormat formats -0.0 as +0.0 + * See also older related bug 4106658, 4106667 + */ +void NumberFormatRegressionTest::Test4147706(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = new DecimalFormat("#,##0.0##", status); + failure(status, "new DecimalFormat"); + DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getEnglish(), status); + failure(status, "new DecimalFormatSymbols"); + UnicodeString f1; + UnicodeString f2, temp; + FieldPosition pos(FieldPosition::DONT_CARE); + volatile double d1 = 0.0; // volatile to prevent code optimization + double d2 = -0.0001; + +#if defined(U_HPUX) + d1 = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword +#else + d1 *= -1.0; // Some compilers have a problem with defining -0.0 +#endif + df->adoptDecimalFormatSymbols(syms); + f1 = df->format(d1, f1, pos); + f2 = df->format(d2, f2, pos); + if (f1 != UnicodeString("-0.0")) { + errln(UnicodeString("") + d1 + UnicodeString(" x \"") + df->toPattern(temp) + "\" is formatted as \"" + f1 + '"'); + } + if (f2 != UnicodeString("-0.0")) { + errln(UnicodeString("") + d2 + UnicodeString(" x \"") + df->toPattern(temp) + "\" is formatted as \"" + f2 + '"'); + } + + delete df; +} + + +// Not applicable, since no serialization in C++ +/*class myformat implements Serializable +{ +DateFormat _dateFormat = DateFormat.getDateInstance(); + +public String Now() +{ + GregorianCalendar calendar = new GregorianCalendar(); + Date t = calendar.getTime(); + String nowStr = _dateFormat.format(t); + return nowStr; +} +}*/ + +/** + * @bug 4162198 + * NumberFormat cannot format Double.MAX_VALUE + */ +// TODO: make this test actually test something +void +NumberFormatRegressionTest::Test4162198(void) +{ + // for some reason, DBL_MAX will not round trip. (bug in sprintf/atof) + double dbl = INT32_MAX * 1000.0; + UErrorCode status = U_ZERO_ERROR; + NumberFormat *f = NumberFormat::createInstance(status); + if(U_FAILURE(status)) { + errln("Couldn't create number format"); + return; + } + f->setMaximumFractionDigits(INT32_MAX); + f->setMaximumIntegerDigits(INT32_MAX); + UnicodeString s; + f->format(dbl,s); + logln(UnicodeString("The number ") + dbl + " formatted to " + s); + Formattable n; + //try { + f->parse(s, n, status); + if(U_FAILURE(status)) + errln("Couldn't parse!"); + //} catch (java.text.ParseException e) { + // errln("Caught a ParseException:"); + // e.printStackTrace(); + //} + + //logln("The string " + s + " parsed as " + n); + + // {dlf} The old code assumes n is a double, but it isn't any more... + // Formattable apparently does not and never did interconvert... too bad. + //if(n.getDouble() != dbl) { + // errln("Round trip failure"); + //} + if (n.getInt64() != dbl) { + errln("Round trip failure"); + } + + delete f; +} + +/** + * @bug 4162852 + * NumberFormat does not parse negative zero. + */ +void +NumberFormatRegressionTest::Test4162852(void) +{ + UErrorCode status = U_ZERO_ERROR; + for(int32_t i=0; i < 2; ++i) { + NumberFormat *f = (i == 0) ? NumberFormat::createInstance(status) + : NumberFormat::createPercentInstance(status); + if(U_FAILURE(status)) { + errln("Couldn't create number format"); + return; + } + double d = 0.0; + d *= -1.0; + UnicodeString s; + f->format(d, s); + Formattable n; + f->parse(s, n, status); + if(U_FAILURE(status)) + errln("Couldn't parse!"); + double e = n.getDouble(); + logln(UnicodeString("") + + d + " -> " + + '"' + s + '"' + " -> " + e); +#if (defined(OS390) && !defined(IEEE_754)) || defined(OS400) + if (e != 0.0) { +#else + if (e != 0.0 || 1.0/e > 0.0) { +#endif + logln("Failed to parse negative zero"); + } + delete f; + } +} + +static double _u_abs(double a) { return a<0?-a:a; } + +/** + * May 17 1999 sync up - liu + * @bug 4167494 + * NumberFormat truncates data + */ +void NumberFormatRegressionTest::Test4167494(void) { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status); + if (failure(status, "NumberFormat::createInstance")){ + delete fmt; + return; + }; + + double a = DBL_MAX * 0.99; // DBL_MAX itself overflows to +Inf + UnicodeString s; + fmt->format(a, s); + Formattable num; + fmt->parse(s, num, status); + failure(status, "Parse"); + if (num.getType() == Formattable::kDouble && + _u_abs(num.getDouble() - a) / a < 0.01) { // RT within 1% + logln(UnicodeString("") + a + " -> \"" + s + "\" -> " + + toString(num) + " ok"); + } else { + errln(UnicodeString("") + a + " -> \"" + s + "\" -> " + + toString(num) + " FAIL"); + } + + // We don't test Double.MIN_VALUE because the locale data for the US + // currently doesn't specify enough digits to display Double.MIN_VALUE. + // This is correct for now; however, we leave this here as a reminder + // in case we want to address this later. + + delete fmt; +} + +/** + * May 17 1999 sync up - liu + * @bug 4170798 + * DecimalFormat.parse() fails when ParseIntegerOnly set to true + */ +void NumberFormatRegressionTest::Test4170798(void) { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status); + if (failure(status, "NumberFormat::createInstance")){ + delete nf; + return; + }; + if(nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) { + errln("DecimalFormat needed to continue"); + return; + } + DecimalFormat *df = (DecimalFormat*) nf; + df->setParseIntegerOnly(TRUE); + Formattable n; + ParsePosition pos(0); + df->parse("-0.0", n, pos); + if (n.getType() != Formattable::kLong + || n.getLong() != 0) { + errln(UnicodeString("FAIL: parse(\"-0.0\") returns ") + toString(n)); + } + delete nf; +} + +/** + * May 17 1999 sync up - liu + * toPattern only puts the first grouping separator in. + */ +void NumberFormatRegressionTest::Test4176114(void) { + const char* DATA[] = { + "00", "#00", + "000", "#000", // No grouping + "#000", "#000", // No grouping + "#,##0", "#,##0", + "#,000", "#,000", + "0,000", "#0,000", + "00,000", "#00,000", + "000,000", "#,000,000", + "0,000,000,000,000.0000", "#0,000,000,000,000.0000", // Reported + }; + int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0])); + UErrorCode status = U_ZERO_ERROR; + UnicodeString s; + for (int i=0; i<DATA_length; i+=2) { + DecimalFormat df(DATA[i], status); + failure(status, "DecimalFormat constructor"); + df.toPattern(s); + UnicodeString exp(DATA[i+1]); + if (s != exp) { + errln(UnicodeString("FAIL: ") + DATA[i] + " -> " + + s + ", want " + exp); + } + } +} + +/** + * May 17 1999 sync up - liu + * @bug 4179818 + * DecimalFormat is incorrectly rounding numbers like 1.2501 to 1.2 + */ +void NumberFormatRegressionTest::Test4179818(void) { + const char* DATA[] = { + // Input Pattern Expected output + "1.2511", "#.#", "1.3", + "1.2501", "#.#", "1.3", + "0.9999", "#", "1", + }; + int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0])); + double DOUBLE[] = { + 1.2511, + 1.2501, + 0.9999, + }; + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym(Locale::getUS(), status); + failure(status, "Construct DecimalFormatSymbols"); + DecimalFormat fmt("#", sym, status); + failure(status, "Construct DecimalFormat"); + for (int i=0; i<DATA_length; i+=3) { + double in = DOUBLE[i/3]; + UnicodeString pat(DATA[i+1]); + UnicodeString exp(DATA[i+2]); + fmt.applyPattern(pat, status); + failure(status, "applyPattern"); + UnicodeString out; + FieldPosition pos; + fmt.format(in, out, pos); + if (out == exp) { + logln(UnicodeString("Ok: ") + in + " x " + pat + " = " + out); + } else { + errln(UnicodeString("FAIL: ") + in + " x " + pat + " = " + out + + ", expected " + exp); + } + } +} + +/** + * May 17 1999 sync up - liu + * Some DecimalFormatSymbols changes are not picked up by DecimalFormat. + * This includes the minus sign, currency symbol, international currency + * symbol, percent, and permille. This is filed as bugs 4212072 and + * 4212073. + */ +void NumberFormatRegressionTest::Test4212072(void) { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym(Locale::getUS(), status); + + failure(status, "DecimalFormatSymbols ct", Locale::getUS()); + DecimalFormat fmt(UnicodeString("#"), sym, status); + failure(status, "DecimalFormat ct", Locale::getUS()); + + UnicodeString s; + FieldPosition pos; + + sym.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, (UChar)0x5e); + fmt.setDecimalFormatSymbols(sym); + s.remove(); + if (fmt.format((int32_t)-1, s, pos) != UNICODE_STRING("^1", 2)) { + errln(UnicodeString("FAIL: -1 x (minus=^) -> ") + s + + ", exp ^1"); + } + s.remove(); + if (fmt.getNegativePrefix(s) != UnicodeString((UChar)0x5e)) { + errln(UnicodeString("FAIL: (minus=^).getNegativePrefix -> ") + + s + ", exp ^"); + } + sym.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, (UChar)0x2d); + + fmt.applyPattern(UnicodeString("#%"), status); + failure(status, "applyPattern percent"); + sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UChar)0x5e); + fmt.setDecimalFormatSymbols(sym); + s.remove(); + if (fmt.format(0.25, s, pos) != UNICODE_STRING("25^", 3)) { + errln(UnicodeString("FAIL: 0.25 x (percent=^) -> ") + s + + ", exp 25^"); + } + s.remove(); + if (fmt.getPositiveSuffix(s) != UnicodeString((UChar)0x5e)) { + errln(UnicodeString("FAIL: (percent=^).getPositiveSuffix -> ") + + s + ", exp ^"); + } + sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UChar)0x25); + + fmt.applyPattern(str("#\\u2030"), status); + failure(status, "applyPattern permill"); + sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, (UChar)0x5e); + fmt.setDecimalFormatSymbols(sym); + s.remove(); + if (fmt.format(0.25, s, pos) != UNICODE_STRING("250^", 4)) { + errln(UnicodeString("FAIL: 0.25 x (permill=^) -> ") + s + + ", exp 250^"); + } + s.remove(); + if (fmt.getPositiveSuffix(s) != UnicodeString((UChar)0x5e)) { + errln(UnicodeString("FAIL: (permill=^).getPositiveSuffix -> ") + + s + ", exp ^"); + } + sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, (UChar)0x2030); + + fmt.applyPattern(str("\\u00A4#.00"), status); + failure(status, "applyPattern currency"); + sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "usd"); + fmt.setDecimalFormatSymbols(sym); + s.remove(); + if (fmt.format(12.5, s, pos) != UnicodeString("usd12.50")) { + errln(UnicodeString("FAIL: 12.5 x (currency=usd) -> ") + s + + ", exp usd12.50"); + } + s.remove(); + if (fmt.getPositivePrefix(s) != UnicodeString("usd")) { + errln(UnicodeString("FAIL: (currency=usd).getPositivePrefix -> ") + + s + ", exp usd"); + } + sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "$"); + + fmt.applyPattern(str("\\u00A4\\u00A4#.00"), status); + failure(status, "applyPattern intl currency"); + sym.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, "DOL"); + fmt.setDecimalFormatSymbols(sym); + s.remove(); + if (fmt.format(12.5, s, pos) != UnicodeString("DOL12.50")) { + errln(UnicodeString("FAIL: 12.5 x (intlcurrency=DOL) -> ") + s + + ", exp DOL12.50"); + } + s.remove(); + if (fmt.getPositivePrefix(s) != UnicodeString("DOL")) { + errln(UnicodeString("FAIL: (intlcurrency=DOL).getPositivePrefix -> ") + + s + ", exp DOL"); + } + sym.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, "USD"); + + // Since the pattern logic has changed, make sure that patterns round + // trip properly. Test stream in/out integrity too. + int32_t n; + const Locale* avail = NumberFormat::getAvailableLocales(n); + static const char* type[] = { + "", + "$ ", + "% ", + }; + for (int i=0; i<n; ++i) { + for (int j=0; j<3; ++j) { + status = U_ZERO_ERROR; + NumberFormat *nf; + switch (j) { + case 0: + nf = NumberFormat::createInstance(avail[i], status); + failure(status, "createInstance", avail[i]); + break; + case 1: + nf = NumberFormat::createCurrencyInstance(avail[i], status); + failure(status, "createCurrencyInstance", avail[i]); + break; + default: + nf = NumberFormat::createPercentInstance(avail[i], status); + failure(status, "createPercentInstance", avail[i]); + break; + } + if (U_FAILURE(status)) { + continue; + } + DecimalFormat *df = (DecimalFormat*) nf; + + // Test toPattern/applyPattern round trip + UnicodeString pat; + df->toPattern(pat); + DecimalFormatSymbols symb(avail[i], status); + failure(status, "Construct DecimalFormatSymbols", avail[i]); + DecimalFormat f2(pat, symb, status); + if (failure(status, + UnicodeString("Construct DecimalFormat(") + pat + ")")) { + continue; + } + if (*df != f2) { + UnicodeString l, p; + errln(UnicodeString("FAIL: ") + type[j] + avail[i].getDisplayName(l) + + " -> \"" + pat + + "\" -> \"" + f2.toPattern(p) + "\""); + } + + // Test toLocalizedPattern/applyLocalizedPattern round trip + df->toLocalizedPattern(pat); + f2.applyLocalizedPattern(pat, status); + failure(status, + UnicodeString("applyLocalizedPattern(") + pat + ")", avail[i]); + if (U_FAILURE(status)) { + continue; + } + + // Make sure we set the currency attributes appropriately + if (j == 1) { // Currency format + f2.setCurrency(f2.getCurrency(), status); + } + failure(status, + UnicodeString("setCurrency() for (") + pat + ")", avail[i]); + if (U_FAILURE(status)) { + continue; + } + + if (*df != f2) { + UnicodeString l, p; + errln(UnicodeString("FAIL: ") + type[j] + avail[i].getDisplayName(l) + + " -> localized \"" + pat + + "\" -> \"" + f2.toPattern(p) + "\""); + } + + delete nf; + + // Test writeObject/readObject round trip + // NOT ON ICU -- Java only + } + } +} + +/** + * May 17 1999 sync up - liu + * DecimalFormat.parse() fails for mulipliers 2^n. + */ +void NumberFormatRegressionTest::Test4216742(void) { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *fmt = (DecimalFormat*) NumberFormat::createInstance(Locale::getUS(), status); + if (failure(status, "createInstance", Locale::getUS())){ + delete fmt; + return; + }; + int32_t DATA[] = { INT32_MIN, INT32_MAX, -100000000, 100000000 }; + int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0])); + for (int i=0; i<DATA_length; ++i) { + UnicodeString str((UnicodeString)"" + DATA[i]); + for (int m = 1; m <= 100; m++) { + fmt->setMultiplier(m); + Formattable num; + fmt->parse(str, num, status); + failure(status, "parse", Locale::getUS()); + if (num.getType() != Formattable::kLong && + num.getType() != Formattable::kDouble) { + errln(UnicodeString("FAIL: Wanted number, got ") + + toString(num)); + } else { + double d = num.getType() == Formattable::kDouble ? + num.getDouble() : (double) num.getLong(); + if (d > 0 != DATA[i] > 0) { + errln(UnicodeString("\"") + str + "\" parse(x " + + fmt->getMultiplier() + + ") => " + toString(num)); + } + } + } + } + delete fmt; +} + +/** + * May 17 1999 sync up - liu + * DecimalFormat formats 1.001 to "1.00" instead of "1" with 2 fraction + * digits. + */ +void NumberFormatRegressionTest::Test4217661(void) { + const double D[] = { 0.001, 1.001, 0.006, 1.006 }; + const char* S[] = { "0", "1", "0.01", "1.01" }; + int D_length = (int)(sizeof(D) / sizeof(D[0])); + UErrorCode status = U_ZERO_ERROR; + NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status); + if (failure(status, "createInstance", Locale::getUS())){ + delete fmt; + return; + }; + fmt->setMaximumFractionDigits(2); + for (int i=0; i<D_length; i++) { + UnicodeString s; + fmt->format(D[i], s); + if (s != UnicodeString(S[i])) { + errln(UnicodeString("FAIL: Got ") + s + ", exp " + S[i]); + } + } + delete fmt; +} + +/** + * alphaWorks upgrade + */ +void NumberFormatRegressionTest::Test4161100(void) { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status); + if (failure(status, "createInstance", Locale::getUS())){ + delete nf; + return; + }; + nf->setMinimumFractionDigits(1); + nf->setMaximumFractionDigits(1); + double a = -0.09; + UnicodeString s; + nf->format(a, s); + UnicodeString pat; + logln(UnicodeString() + a + " x " + + ((DecimalFormat*) nf)->toPattern(pat) + " = " + s); + if (s != UnicodeString("-0.1")) { + errln("FAIL"); + } + delete nf; +} + +/** + * June 16 1999 sync up - liu + * Formatting .5 rounds to "1" instead of "0". (Regression in 1.2.2 RC1) + */ +void NumberFormatRegressionTest::Test4243011(void) { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym(Locale::getUS(), status); + failure(status, "DecimalFormatSymbols ct", Locale::getUS()); + DecimalFormat fmt(UnicodeString("0."), sym, status); + failure(status, "DecimalFormat ct", Locale::getUS()); + + const double NUM[] = { -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5 }; + const char* STR[] = { "-2.", "-2.", "-0.", "0.", "2.", "2.", "4.", "4." }; + int32_t N = (int32_t)(sizeof(NUM) / sizeof(NUM[0])); + + for (int32_t i=0; i<N; ++i) { + UnicodeString str; + UnicodeString exp(STR[i]); + FieldPosition pos; + fmt.format(NUM[i], str, pos); + if (str == exp) { + logln(UnicodeString("Ok ") + NUM[i] + " x 0. = " + str); + } else { + errln(UnicodeString("FAIL ") + NUM[i] + " x 0. = " + str + + ", want " + exp); + } + } +} + +/** + * June 16 1999 sync up - liu + * format(0.0) gives "0.1" if preceded by parse("99.99"). + * (Regression in 1.2.2 RC1) + */ +void NumberFormatRegressionTest::Test4243108(void) { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym(Locale::getUS(), status); + failure(status, "DecimalFormatSymbols ct", Locale::getUS()); + DecimalFormat fmt(UnicodeString("#.#"), sym, status); + failure(status, "DecimalFormat ct", Locale::getUS()); + + UnicodeString str; + FieldPosition pos; + + fmt.format(0.0, str, pos); + UnicodeString exp("0"); + if (str == exp) { + logln(UnicodeString("Ok 0.0 x #.# = ") + str); + } else { + errln(UnicodeString("FAIL 0.0 x #.# = ") + str + + ", want " + exp); + } + + str = "99.99"; + Formattable val; + fmt.parse(str, val, status); + failure(status, "DecimalFormat.parse(99.99)", Locale::getUS()); + if (val.getType() == Formattable::kDouble && + val.getDouble() == 99.99) { + logln(UnicodeString("Ok 99.99 / #.# = ") + toString(val)); + } else { + errln(UnicodeString("FAIL 99.99 / #.# = ") + toString(val) + + ", want " + 99.99); + } + + str.remove(); + fmt.format(0.0, str, pos); + if (str == exp) { + logln(UnicodeString("Ok 0.0 x #.# = ") + str); + } else { + errln(UnicodeString("FAIL 0.0 x #.# = ") + str + + ", want " + exp); + } +} + + +/** + * DateFormat should call setIntegerParseOnly(TRUE) on adopted + * NumberFormat objects. + */ +void NumberFormatRegressionTest::TestJ691(void) { + UErrorCode status = U_ZERO_ERROR; + Locale loc("fr", "CH"); + + // set up the input date string & expected output + UnicodeString udt("11.10.2000", ""); + UnicodeString exp("11.10.00", ""); + + // create a Calendar for this locale + Calendar *cal = Calendar::createInstance(loc, status); + if (U_FAILURE(status)) { + errln("FAIL: Calendar::createInstance() returned " + (UnicodeString)u_errorName(status)); + return; + } + + // create a NumberFormat for this locale + NumberFormat *nf = NumberFormat::createInstance(loc, status); + if (U_FAILURE(status)) { + errln("FAIL: NumberFormat::createInstance() returned " + (UnicodeString)u_errorName(status)); + return; + } + + // *** Here's the key: We don't want to have to do THIS: + // nf->setParseIntegerOnly(TRUE); + + // create the DateFormat + DateFormat *df = DateFormat::createDateInstance(DateFormat::kShort, loc); + if (U_FAILURE(status)) { + errln("FAIL: DateFormat::createInstance() returned " + (UnicodeString)u_errorName(status)); + return; + } + + df->adoptCalendar(cal); + df->adoptNumberFormat(nf); + + // set parsing to lenient & parse + df->setLenient(TRUE); + UDate ulocdat = df->parse(udt, status); + + // format back to a string + UnicodeString outString; + df->format(ulocdat, outString); + + if (outString != exp) { + errln("FAIL: " + udt + " => " + outString); + } + + delete df; +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ |