You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3069 lines
105 KiB
3069 lines
105 KiB
// © 2016 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
/***********************************************************************
|
|
* Copyright (c) 1997-2016, International Business Machines Corporation
|
|
* and others. All Rights Reserved.
|
|
***********************************************************************/
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
|
|
#include "numrgts.h"
|
|
|
|
#include <cmath> // std::signbit
|
|
#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 "cmemory.h"
|
|
#include "cstr.h"
|
|
#include "putilimp.h"
|
|
#include "uassert.h"
|
|
|
|
class MyNumberFormatTest : public NumberFormat
|
|
{
|
|
public:
|
|
|
|
virtual UClassID getDynamicClassID(void) const;
|
|
|
|
virtual UnicodeString& format( double number,
|
|
UnicodeString& toAppendTo,
|
|
FieldPositionIterator* posIter,
|
|
UErrorCode& status) const
|
|
{
|
|
return NumberFormat::format(number, toAppendTo, posIter, 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 MyNumberFormatTest* 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);
|
|
CASE(61,Test8199);
|
|
CASE(62,Test9109);
|
|
CASE(63,Test9780);
|
|
CASE(64,Test9677);
|
|
CASE(65,Test10361);
|
|
|
|
default: name = ""; break;
|
|
}
|
|
}
|
|
|
|
UBool
|
|
NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, const Locale& l, UBool possibleDataError)
|
|
{
|
|
if(U_FAILURE(status)) {
|
|
if (possibleDataError) {
|
|
dataerrln(UnicodeString("FAIL: ", "") + msg
|
|
+ UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l.getName(),""));
|
|
} else {
|
|
errcheckln(status, 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, UBool possibleDataError)
|
|
{
|
|
if(U_FAILURE(status)) {
|
|
if (possibleDataError) {
|
|
dataerrln(UnicodeString("FAIL: ", "") + msg
|
|
+ UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l, ""));
|
|
} else {
|
|
errcheckln(status, UnicodeString("FAIL: ", "") + msg
|
|
+ UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l, ""));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UBool
|
|
NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, UBool possibleDataError)
|
|
{
|
|
if(U_FAILURE(status)) {
|
|
if (possibleDataError) {
|
|
dataerrln(UnicodeString("FAIL: ", "") + msg
|
|
+ UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), ""));
|
|
} else {
|
|
errcheckln(status, 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);
|
|
if (!failure(status, "new DecimalFormat", "")) {
|
|
double d = 100;
|
|
df->setMinimumFractionDigits(0);
|
|
df->setMaximumFractionDigits(16);
|
|
UnicodeString sBuf1;
|
|
FieldPosition fp1(FieldPosition::DONT_CARE);
|
|
logln(UnicodeString("d = ") + d);
|
|
logln(UnicodeString("maxFractionDigits = ") + df->getMaximumFractionDigits());
|
|
|
|
logln(" format(d) = '" + df->format(d, sBuf1, fp1) + "'");
|
|
df->setMaximumFractionDigits(17);
|
|
UnicodeString sBuf2;
|
|
FieldPosition fp2(FieldPosition::DONT_CARE);
|
|
logln(UnicodeString("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);
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
|
|
return;
|
|
}
|
|
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);
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
|
|
return;
|
|
}
|
|
df->setGroupingSize(0);
|
|
UnicodeString sBuf;
|
|
FieldPosition fp(FieldPosition::DONT_CARE);
|
|
//try {
|
|
logln(df->format((int32_t)123, sBuf, fp));
|
|
//if(fp == FieldPosition(FieldPosition::DONT_CARE))
|
|
// 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(), TRUE)){
|
|
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(), TRUE)) {
|
|
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)) {
|
|
dataerrln("Something is wrong with French number format - it should not fallback. Exitting - %s", u_errorName(status));
|
|
delete nf1;
|
|
return;
|
|
}
|
|
failure(status, "NumberFormat::createInstance", Locale::getFrance());
|
|
|
|
// C++ workaround to make sure cast works
|
|
DecimalFormat *nf = dynamic_cast<DecimalFormat *>(nf1);
|
|
if(nf == NULL) {
|
|
errln("NumberFormat::createInstance returned incorrect type.");
|
|
return;
|
|
}
|
|
|
|
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, 0x202f, 0x23, 0x23, 0x23, 0x2c, 0x30, 0x30, 0x3b,
|
|
0x28, 0x23, 0x202f, 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, 0x202f, 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, 0x202f, 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)) {
|
|
errcheckln(status, "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)) {
|
|
errcheckln(status, "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(FieldPosition::DONT_CARE);
|
|
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)) {
|
|
errcheckln(status, "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(UnicodeString(" getMaximumFractionDigits() = ") + i);
|
|
logln(UnicodeString(" 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)) {
|
|
errcheckln(status, "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)) {
|
|
errcheckln(status, "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)) {
|
|
errcheckln(status, "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("ERROR: 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("ERROR: 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("ERROR: 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("ERROR: 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@currency=PTE", loc, 256, &status);
|
|
Locale de(loc);
|
|
LocalPointer<NumberFormat> nf(NumberFormat::createCurrencyInstance(de, status));
|
|
if(U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormat: %s", u_errorName(status));
|
|
return;
|
|
}
|
|
DecimalFormat *df = dynamic_cast<DecimalFormat *>(nf.getAlias());
|
|
if(df == NULL) {
|
|
errln("expected DecimalFormat!");
|
|
return;
|
|
}
|
|
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 + '"');
|
|
}
|
|
}
|
|
/* @bug 4070798
|
|
* Number format data rounding errors for locale FR
|
|
*/
|
|
void NumberFormatRegressionTest::Test4070798 (void)
|
|
{
|
|
NumberFormat *formatter;
|
|
UnicodeString tempString;
|
|
|
|
/* User error :
|
|
String expectedDefault = "-5\u202f789,987";
|
|
String expectedCurrency = "5\u202f789,98\u00a0F";
|
|
String expectedPercent = "-578\u202f998%";
|
|
*/
|
|
UChar chars1 [] = {
|
|
0x2d, 0x35, 0x202f, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x38, 0x38
|
|
};
|
|
UChar chars2 [] = {
|
|
0x35, 0x202f, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x39, 0x00a0, 0x46
|
|
};
|
|
UChar chars3 [] = {
|
|
0x2d, 0x35, 0x37, 0x38, 0x202f, 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@currency=FRF", loc, 256, &status);
|
|
(void)len; // Suppress set but not used warning.
|
|
formatter = NumberFormat::createInstance(Locale(loc), status);
|
|
if(U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormat: %s", u_errorName(status));
|
|
delete formatter;
|
|
return;
|
|
}
|
|
failure(status, "NumberFormat::createInstance", 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@currency=FRF", 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@currency=FRF", 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\u00a0$\u00a0CA";
|
|
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, 0x00a0, 0x24, 0x00a0, 0x43, 0x41
|
|
};
|
|
UChar chars3 [] = {
|
|
0x2d, 0x35, 0x37, 0x38, 0x00a0, 0x39, 0x39, 0x39, 0x00a0, 0x25
|
|
};
|
|
UnicodeString expectedDefault(chars1, 10, 10);
|
|
UnicodeString expectedCurrency(chars2, 13, 13);
|
|
UnicodeString expectedPercent(chars3, 10, 10);
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
formatter = NumberFormat::createInstance(Locale::getCanadaFrench(), status);
|
|
if (failure(status, "NumberFormat::createInstance", Locale::getCanadaFrench(), TRUE)){
|
|
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\\u00A0DM");
|
|
UnicodeString expectedPercent("-578.999\\u00A0%");
|
|
|
|
expectedCurrency = expectedCurrency.unescape();
|
|
expectedPercent = expectedPercent.unescape();
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
char loc[256]={0};
|
|
uloc_canonicalize("de_DE@currency=DEM", loc, 256, &status);
|
|
formatter = NumberFormat::createInstance(Locale(loc), status);
|
|
if (failure(status, "NumberFormat::createInstance", loc, TRUE)){
|
|
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@currency=DEM", 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.\\u00A05.789,98";
|
|
String expectedPercent = "-578.998%";
|
|
*/
|
|
UnicodeString expectedDefault("-5.789,988");
|
|
UnicodeString expectedCurrency("-ITL\\u00A05.790", -1, US_INV);
|
|
UnicodeString expectedPercent("-578.999%");
|
|
expectedCurrency = expectedCurrency.unescape();
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
char loc[256]={0};
|
|
uloc_canonicalize("it_IT@currency=ITL", loc, 256, &status);
|
|
formatter = NumberFormat::createInstance(Locale(loc), status);
|
|
if (failure(status, "NumberFormat::createNumberInstance", TRUE)){
|
|
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@currency=ITL", 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@currency=ITL", 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("#0.#", status);
|
|
if (!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);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
dataerrln("FAIL: Expected '%s'; got '%s'", CStr(expected)(), CStr(out)());
|
|
}
|
|
}
|
|
/* @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)) {
|
|
errcheckln(status, "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"))
|
|
dataerrln("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)) {
|
|
errcheckln(status, "Error creating DecimalFormat: %s", u_errorName(status));
|
|
delete sdf;
|
|
return;
|
|
}
|
|
failure(status, "new DecimalFormat");
|
|
if (sdf->getMinimumIntegerDigits() != 1)
|
|
errln(UnicodeString("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)) {
|
|
errcheckln(status, "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);
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormatSymbols - %s", u_errorName(status));
|
|
return;
|
|
}
|
|
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);
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
|
|
return;
|
|
}
|
|
UnicodeString formatted;
|
|
FieldPosition field(FieldPosition::DONT_CARE);
|
|
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)) {
|
|
errcheckln(status, "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)) {
|
|
errcheckln(status, "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 U_PLATFORM == U_PF_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)) {
|
|
errcheckln(status, "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)) {
|
|
dataerrln("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)) {
|
|
errcheckln(status, "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)) {
|
|
errcheckln(status, "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 U_PLATFORM == U_PF_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.
|
|
*/
|
|
#if U_PLATFORM == U_PF_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)) {
|
|
dataerrln("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(UnicodeString("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->getWithFallback("NumberElements", status);
|
|
failure(status, "rb.get(NumberElements)");
|
|
numPat = numPat.getWithFallback("latn",status);
|
|
failure(status, "rb.get(latn)");
|
|
numPat = numPat.getWithFallback("patterns",status);
|
|
failure(status, "rb.get(patterns)");
|
|
numPat = numPat.getWithFallback("currencyFormat",status);
|
|
failure(status, "rb.get(currencyFormat)");
|
|
//
|
|
// 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.getString(status);
|
|
failure(status, "rb->getString()");
|
|
|
|
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");
|
|
|
|
// Disable currency spacing for the purposes of this test.
|
|
// To do this, set the spacing insert to the empty string both before and after the symbol.
|
|
symbols->setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, FALSE, u"");
|
|
symbols->setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, u"");
|
|
|
|
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)) {
|
|
errcheckln(status, "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);
|
|
if (!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);
|
|
if (!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;
|
|
LocalPointer<DecimalFormatSymbols> syms(new DecimalFormatSymbols(Locale::getEnglish(), status), status);
|
|
if (failure(status, "new DecimalFormatSymbols")) {
|
|
return;
|
|
}
|
|
DecimalFormat *f = new DecimalFormat(UnicodeString(u""), syms.orphan(), status);
|
|
if (!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", TRUE)){
|
|
delete nff;
|
|
return;
|
|
}
|
|
DecimalFormat *nf = dynamic_cast<DecimalFormat *>(nff);
|
|
if(nf == NULL) {
|
|
errln("DecimalFormat needed to continue");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
pp.setIndex(0);
|
|
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
|
|
*
|
|
* ICU 62: minInt is always at least one, and the getter should reflect that!
|
|
*/
|
|
void NumberFormatRegressionTest::Test4147295(void)
|
|
{
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
DecimalFormat *sdf = new DecimalFormat(status);
|
|
UnicodeString pattern("#,###");
|
|
logln("Applying pattern \"" + pattern + "\"");
|
|
sdf->applyPattern(pattern, status);
|
|
if (!failure(status, "sdf->applyPattern")) {
|
|
int minIntDig = sdf->getMinimumIntegerDigits();
|
|
if (minIntDig != 1) {
|
|
errln("Test failed");
|
|
errln(UnicodeString(" Minimum integer digits : ") + minIntDig);
|
|
UnicodeString temp;
|
|
errln(UnicodeString(" new pattern: ") + sdf->toPattern(temp));
|
|
} else {
|
|
logln("Test passed");
|
|
logln(UnicodeString(" 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);
|
|
if (!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 U_PLATFORM == U_PF_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)) {
|
|
dataerrln("Couldn't create number format - %s", u_errorName(status));
|
|
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) {
|
|
LocalPointer<NumberFormat> f(
|
|
((i == 0) ? NumberFormat::createInstance(status) : NumberFormat::createPercentInstance(status)),
|
|
status);
|
|
if(U_FAILURE(status)) {
|
|
dataerrln("Couldn't create number format - %s", u_errorName(status));
|
|
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!");
|
|
return;
|
|
}
|
|
double e = n.getDouble();
|
|
logln("%f -> \"%s\" -> %f", d, CStr(s)(), e);
|
|
#if (U_PLATFORM == U_PF_OS390 && !defined(IEEE_754)) || U_PLATFORM == U_PF_OS400
|
|
if (e != 0.0) {
|
|
#else
|
|
if (e != 0.0 || (std::signbit(e) == false)) {
|
|
#endif
|
|
errln("Failed to parse negative zero");
|
|
}
|
|
}
|
|
}
|
|
|
|
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", TRUE)){
|
|
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) {
|
|
IcuTestErrorCode status(*this, "Test4170798");
|
|
LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>(
|
|
NumberFormat::createInstance(Locale::getUS(), status)), status);
|
|
if (!assertSuccess("", status, true, __FILE__, __LINE__)) {
|
|
return;
|
|
}
|
|
{
|
|
Formattable n;
|
|
ParsePosition pos(0);
|
|
df->parse("-0.0", n, pos);
|
|
if (n.getType() != Formattable::kDouble
|
|
|| n.getDouble() != -0.0) {
|
|
errln(UnicodeString("FAIL: default parse(\"-0.0\") returns ") + toString(n));
|
|
}
|
|
}
|
|
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: integer parse(\"-0.0\") returns ") + toString(n));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 = UPRV_LENGTHOF(DATA);
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
UnicodeString s;
|
|
for (int i=0; i<DATA_length; i+=2) {
|
|
DecimalFormat df(DATA[i], status);
|
|
if (!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 = UPRV_LENGTHOF(DATA);
|
|
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);
|
|
if (!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);
|
|
if(failure(status, "DecimalFormat ct", Locale::getUS())) {
|
|
return;
|
|
}
|
|
|
|
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(u"usd\u00A012.50")) {
|
|
errln(UnicodeString("FAIL: 12.5 x (currency=usd) -> ") + s +
|
|
u", exp usd\u00A012.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(u"DOL\u00A012.50")) {
|
|
errln(UnicodeString("FAIL: 12.5 x (intlcurrency=DOL) -> ") + s +
|
|
u", exp DOL\u00A012.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) + "\"");
|
|
} else {
|
|
UnicodeString l, p;
|
|
logln(UnicodeString("PASS: ") + type[j] + avail[i].getDisplayName(l) +
|
|
" -> \"" + pat +
|
|
"\"");
|
|
}
|
|
|
|
// Test toLocalizedPattern/applyLocalizedPattern round trip
|
|
// TODO(refactor): don't worry about localized patterns for now.
|
|
// df->toLocalizedPattern(pat);
|
|
// f2.applyLocalizedPattern(pat, status);
|
|
failure(status,
|
|
UnicodeString("applyLocalizedPattern(") + pat + ")", avail[i]);
|
|
if (U_FAILURE(status)) {
|
|
continue;
|
|
}
|
|
|
|
// TODO(refactor): don't worry about localized patterns for now.
|
|
// 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(), TRUE)){
|
|
delete fmt;
|
|
return;
|
|
}
|
|
int32_t DATA[] = { INT32_MIN, INT32_MAX, -100000000, 100000000 };
|
|
int DATA_length = UPRV_LENGTHOF(DATA);
|
|
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 = UPRV_LENGTHOF(D);
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status);
|
|
if (failure(status, "createInstance", Locale::getUS(), TRUE)){
|
|
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(), TRUE)){
|
|
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);
|
|
|
|
if (!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 = UPRV_LENGTHOF(NUM);
|
|
|
|
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);
|
|
if (failure(status, "DecimalFormat ct", Locale::getUS())) {
|
|
return;
|
|
}
|
|
|
|
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(u"11.10.2000");
|
|
UnicodeString exp(u"11.10.00");
|
|
|
|
// create a Calendar for this locale
|
|
LocalPointer<Calendar> cal(Calendar::createInstance(loc, status));
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("FAIL: Calendar::createInstance() returned " + (UnicodeString)u_errorName(status));
|
|
return;
|
|
}
|
|
|
|
// create a NumberFormat for this locale
|
|
LocalPointer<NumberFormat> nf(NumberFormat::createInstance(loc, status));
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("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);
|
|
// or this (with changes to fr_CH per cldrbug:9370):
|
|
// nf->setGroupingUsed(FALSE);
|
|
// so they are done in DateFormat::adoptNumberFormat
|
|
|
|
// create the DateFormat
|
|
LocalPointer<DateFormat> df(DateFormat::createDateInstance(DateFormat::kShort, loc));
|
|
if (U_FAILURE(status)) {
|
|
errln("FAIL: DateFormat::createInstance() returned " + (UnicodeString)u_errorName(status));
|
|
return;
|
|
}
|
|
|
|
df->adoptCalendar(cal.orphan());
|
|
df->adoptNumberFormat(nf.orphan());
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Error Checking / Reporting macros
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#define TEST_CHECK_STATUS(status) UPRV_BLOCK_MACRO_BEGIN { \
|
|
if (U_FAILURE(status)) { \
|
|
if (status == U_MISSING_RESOURCE_ERROR) { \
|
|
dataerrln("File %s, Line %d: status=%s", __FILE__, __LINE__, u_errorName(status)); \
|
|
} else { \
|
|
errln("File %s, Line %d: status=%s", __FILE__, __LINE__, u_errorName(status)); \
|
|
} return; \
|
|
} \
|
|
} UPRV_BLOCK_MACRO_END
|
|
|
|
#define TEST_ASSERT(expr) UPRV_BLOCK_MACRO_BEGIN { \
|
|
if ((expr)==FALSE) {\
|
|
errln("File %s, line %d: Assertion Failed: " #expr "\n", __FILE__, __LINE__);\
|
|
} \
|
|
} UPRV_BLOCK_MACRO_END
|
|
#define TEST_ASSERT_EQUALS(x,y) UPRV_BLOCK_MACRO_BEGIN { \
|
|
char _msg[1000]; \
|
|
int32_t len = sprintf (_msg,"File %s, line %d: " #x "==" #y, __FILE__, __LINE__); \
|
|
(void)len; \
|
|
U_ASSERT(len < (int32_t) sizeof(_msg)); \
|
|
assertEquals((const char*) _msg, x,y); \
|
|
} UPRV_BLOCK_MACRO_END
|
|
|
|
|
|
// Ticket 8199: Parse failure for numbers in the range of 1E10 - 1E18
|
|
|
|
void NumberFormatRegressionTest::Test8199(void) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
NumberFormat *nf = NumberFormat::createInstance(Locale::getEnglish(), status);
|
|
if (nf == NULL) {
|
|
dataerrln("Fail: NumberFormat::createInstance(Locale::getEnglish(), status)");
|
|
return;
|
|
}
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
// Note: Retrieving parsed values from a Formattable as a reduced-precision type
|
|
// should always truncate, no other rounding scheme.
|
|
|
|
UnicodeString numStr = "1000000000.6"; // 9 zeroes
|
|
Formattable val;
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS(1000000000LL, val.getInt64(status));
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(1000000000.6, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "100000000000000001.1"; // approx 1E17, parses as a double rather
|
|
// than int64 because of the fraction
|
|
// even though int64 is more precise.
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS(100000000000000001LL, val.getInt64(status));
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(100000000000000000.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "1E17"; // Parses with the internal decimal number having non-zero exponent
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
|
|
TEST_ASSERT_EQUALS(100000000000000000LL, val.getInt64());
|
|
TEST_ASSERT_EQUALS(1.0E17, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "9223372036854775807"; // largest int64_t
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
|
|
TEST_ASSERT_EQUALS(9223372036854775807LL, val.getInt64());
|
|
// In the following check, note that a substantial range of integers will
|
|
// convert to the same double value. There are also platform variations
|
|
// in the rounding at compile time of double constants.
|
|
TEST_ASSERT(9223372036854775808.0 >= val.getDouble(status));
|
|
TEST_ASSERT(9223372036854774700.0 <= val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "-9223372036854775808"; // smallest int64_t
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
|
|
// TEST_ASSERT_EQUALS(-9223372036854775808LL, val.getInt64()); // Compiler chokes on constant.
|
|
TEST_ASSERT_EQUALS((int64_t)0x8000000000000000LL, val.getInt64());
|
|
TEST_ASSERT_EQUALS(-9223372036854775808.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "9223372036854775808"; // largest int64_t + 1
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS(9223372036854775807LL, val.getInt64(status));
|
|
TEST_ASSERT_EQUALS(status, U_INVALID_FORMAT_ERROR);
|
|
status = U_ZERO_ERROR;
|
|
TEST_ASSERT_EQUALS(9223372036854775810.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
numStr = "-9223372036854775809"; // smallest int64_t - 1
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
// TEST_ASSERT_EQUALS(-9223372036854775808LL, val.getInt64(status)); // spurious compiler warnings
|
|
TEST_ASSERT_EQUALS((int64_t)0x8000000000000000LL, val.getInt64(status));
|
|
TEST_ASSERT_EQUALS(status, U_INVALID_FORMAT_ERROR);
|
|
status = U_ZERO_ERROR;
|
|
TEST_ASSERT_EQUALS(-9223372036854775810.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
// Test values near the limit of where doubles can represent all integers.
|
|
// The implementation strategy of getInt64() changes at this boundary.
|
|
// Strings to be parsed include a decimal fraction to force them to be
|
|
// parsed as doubles rather than ints. The fraction is discarded
|
|
// from the parsed double value because it is beyond what can be represented.
|
|
|
|
status = U_ZERO_ERROR;
|
|
numStr = "9007199254740991.1"; // largest 53 bit int
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
// printf("getInt64() returns %lld\n", val.getInt64(status));
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS(9007199254740991LL, val.getInt64(status));
|
|
TEST_ASSERT_EQUALS(9007199254740991.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
status = U_ZERO_ERROR;
|
|
numStr = "9007199254740992.1"; // 54 bits for the int part.
|
|
nf->parse(numStr, val, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS(9007199254740992LL, val.getInt64(status));
|
|
TEST_ASSERT_EQUALS(9007199254740992.0, val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
status = U_ZERO_ERROR;
|
|
numStr = "9007199254740993.1"; // 54 bits for the int part. Double will round
|
|
nf->parse(numStr, val, status); // the ones digit, putting it up to ...994
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
|
|
TEST_ASSERT_EQUALS((int64_t)9007199254740993LL,val.getInt64(status));
|
|
TEST_ASSERT_EQUALS((double)9007199254740994.0,(double)val.getDouble(status));
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
delete nf;
|
|
}
|
|
|
|
void NumberFormatRegressionTest::Test9109(void) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
Formattable val;
|
|
ParsePosition pos;
|
|
DecimalFormat fmt("+##", status);
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Failed to create DecimalFormat with pattern '+##' - %s", u_errorName(status));
|
|
return;
|
|
}
|
|
|
|
fmt.setLenient(TRUE);
|
|
UnicodeString text("123");
|
|
int32_t expected = 123;
|
|
int32_t expos = 3;
|
|
|
|
fmt.parse(text, val, pos);
|
|
if (pos.getErrorIndex() >= 0) {
|
|
errln(UnicodeString("Parse failure at ") + pos.getErrorIndex());
|
|
} else if (val.getLong() != 123) {
|
|
errln(UnicodeString("Incorrect parse result: ") + val.getLong() + " expected: " + expected);
|
|
} else if (pos.getIndex() != 3) {
|
|
errln(UnicodeString("Incorrect parse position: ") + pos.getIndex() + " expected: " + expos);
|
|
}
|
|
}
|
|
|
|
|
|
void NumberFormatRegressionTest::Test9780(void) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status);
|
|
if (failure(status, "NumberFormat::createInstance", TRUE)){
|
|
delete nf;
|
|
return;
|
|
}
|
|
DecimalFormat *df = dynamic_cast<DecimalFormat *>(nf);
|
|
if(df == NULL) {
|
|
errln("DecimalFormat needed to continue");
|
|
return;
|
|
}
|
|
df->setParseIntegerOnly(TRUE);
|
|
|
|
{
|
|
Formattable n;
|
|
ParsePosition pos(0);
|
|
UnicodeString toParse("1,234","");
|
|
df->parse(toParse, n, pos);
|
|
if (n.getType() != Formattable::kLong
|
|
|| n.getLong() != 1234) {
|
|
errln(UnicodeString("FAIL: parse(\"") + toParse + UnicodeString("\") returns ") + toString(n));
|
|
}
|
|
}
|
|
// should still work in lenient mode, just won't get fastpath
|
|
df->setLenient(TRUE);
|
|
{
|
|
Formattable n;
|
|
ParsePosition pos(0);
|
|
UnicodeString toParse("1,234","");
|
|
df->parse(toParse, n, pos);
|
|
if (n.getType() != Formattable::kLong
|
|
|| n.getLong() != 1234) {
|
|
errln(UnicodeString("FAIL: parse(\"") + toParse + UnicodeString("\") returns ") + toString(n));
|
|
}
|
|
}
|
|
delete nf;
|
|
}
|
|
|
|
|
|
void NumberFormatRegressionTest::Test9677(void) {
|
|
static const UChar pattern[] = { 0x23,0x23,0x23,0x23,0x2E,0x23,0x23,0x23,0x23,0 }; // "####.####"
|
|
static const UChar positivePrefix[] = { 0x40,0 }; // "@"
|
|
static const UChar negativePrefix[] = { 0x6E,0 }; // "n"
|
|
static const UChar text[] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0 }; // 123456789
|
|
static const UChar text2[] = { 0x6E, 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0 }; // n123456789
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
LocalUNumberFormatPointer f(unum_open(UNUM_DEFAULT, NULL, 0, "en_US", NULL, &status));
|
|
if (U_FAILURE(status)) {
|
|
dataerrln("Failure opening unum_open");
|
|
return;
|
|
}
|
|
|
|
if (U_SUCCESS(status)) {
|
|
unum_applyPattern(f.getAlias(), FALSE, pattern, -1, NULL, &status);
|
|
unum_setTextAttribute(f.getAlias(), UNUM_POSITIVE_PREFIX, positivePrefix, -1, &status);
|
|
assertSuccess("setting attributes", status);
|
|
}
|
|
|
|
if(U_SUCCESS(status)) {
|
|
int32_t n = unum_parse(f.getAlias(), text, -1, NULL, &status);
|
|
logln("unum_parse status %s, result %d\n", u_errorName(status), n);
|
|
|
|
if(U_FAILURE(status)) {
|
|
logln("Got expected parse error %s\n", u_errorName(status));
|
|
status = U_ZERO_ERROR;
|
|
} else {
|
|
errln("FAIL: unum_parse status %s, result %d - expected failure\n", u_errorName(status), n);
|
|
}
|
|
}
|
|
|
|
if (U_SUCCESS(status)) {
|
|
unum_setTextAttribute(f.getAlias(), UNUM_POSITIVE_PREFIX, NULL, 0, &status);
|
|
assertSuccess("setting attributes", status);
|
|
logln("removed positive prefix");
|
|
}
|
|
|
|
if(U_SUCCESS(status)) {
|
|
int32_t n = unum_parse(f.getAlias(), text, -1, NULL, &status);
|
|
logln("unum_parse status %s, result %d\n", u_errorName(status), n);
|
|
|
|
if(U_FAILURE(status)) {
|
|
errln("FAIL: with pos prefix removed, parse error %s\n", u_errorName(status));
|
|
status = U_ZERO_ERROR;
|
|
} else {
|
|
if(n!=123456789) {
|
|
errln("FAIL: with pos prefix removed , unum_parse status %s, result %d expected 123456789\n", u_errorName(status), n);
|
|
} else {
|
|
logln("PASS: with pos prefix removed , unum_parse status %s, result %d expected 123456789\n", u_errorName(status),n);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(U_SUCCESS(status)) {
|
|
int32_t n = unum_parse(f.getAlias(), text2, -1, NULL, &status);
|
|
logln("unum_parse status %s, result %d\n", u_errorName(status), n);
|
|
|
|
if(U_FAILURE(status)) {
|
|
logln("text2: Got expected parse error %s\n", u_errorName(status));
|
|
status = U_ZERO_ERROR;
|
|
} else {
|
|
errln("FAIL: text2: unum_parse status %s, result %d - expected failure\n", u_errorName(status), n);
|
|
}
|
|
}
|
|
|
|
if (U_SUCCESS(status)) {
|
|
unum_setTextAttribute(f.getAlias(), UNUM_NEGATIVE_PREFIX, negativePrefix, -1, &status);
|
|
assertSuccess("setting attributes", status);
|
|
logln("Set a different neg prefix prefix");
|
|
}
|
|
|
|
if(U_SUCCESS(status)) {
|
|
int32_t n = unum_parse(f.getAlias(), text2, -1, NULL, &status);
|
|
logln("unum_parse status %s, result %d\n", u_errorName(status), n);
|
|
|
|
if(U_FAILURE(status)) {
|
|
errln("FAIL: with different neg prefix , parse error %s\n", u_errorName(status));
|
|
status = U_ZERO_ERROR;
|
|
} else {
|
|
if(n!=-123456789) {
|
|
errln("FAIL: with different neg prefix , unum_parse status %s, result %d expected -123456789\n", u_errorName(status), n);
|
|
} else {
|
|
logln("PASS: with different neg prefix , unum_parse status %s, result %d expected -123456789\n", u_errorName(status), n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NumberFormatRegressionTest::Test10361(void) {
|
|
// DecimalFormat/NumberFormat were artificially limiting the number of digits,
|
|
// preventing formatting of big decimals.
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
|
|
LocalPointer<DecimalFormat> df(new DecimalFormat("###.##", symbols, status), status);
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
// Create a decimal number with a million digits.
|
|
const int32_t NUMSIZE=1000000;
|
|
char *num = new char[NUMSIZE];
|
|
for (int32_t i=0; i<NUMSIZE; i++) {
|
|
num[i] = '0' + (i+1) % 10;
|
|
}
|
|
num[NUMSIZE-3] = '.';
|
|
num[NUMSIZE-1] = 0;
|
|
|
|
UnicodeString s;
|
|
Formattable fmtable;
|
|
fmtable.setDecimalNumber(num, status);
|
|
TEST_CHECK_STATUS(status);
|
|
|
|
FieldPosition pos(UNUM_DECIMAL_SEPARATOR_FIELD);
|
|
df->format(fmtable, s, pos, status);
|
|
TEST_CHECK_STATUS(status);
|
|
TEST_ASSERT(999999 == s.length());
|
|
TEST_ASSERT(999997 == pos.getBeginIndex());
|
|
TEST_ASSERT(999998 == pos.getEndIndex());
|
|
|
|
UnicodeString expected(num, -1, US_INV);
|
|
TEST_ASSERT(expected == s);
|
|
delete [] num;
|
|
}
|
|
|
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|