blob: bc9fc7fcb8ae2a8c7e4bd5cc982cea9d2b03225d [file] [log] [blame]
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
/* Modification History:
* Date Name Description
* 07/15/99 helena Ported to HPUX 10/11 CC.
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "numfmtst.h"
#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/ucurr.h"
#include "unicode/ustring.h"
#include "unicode/measfmt.h"
#include "unicode/curramt.h"
#include "unicode/strenum.h"
#include "textfile.h"
#include "tokiter.h"
#include "charstr.h"
#include "cstr.h"
#include "putilimp.h"
#include "winnmtst.h"
#include <cmath>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include "cmemory.h"
#include "cstring.h"
#include "unicode/numsys.h"
#include "fmtableimp.h"
#include "numberformattesttuple.h"
#include "unicode/msgfmt.h"
#include "number_decimalquantity.h"
#include "unicode/numberformatter.h"
#if (U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)
// These should not be macros. If they are,
// replace them with std::isnan and std::isinf
#if defined(isnan)
#undef isnan
namespace std {
bool isnan(double x) {
return _isnan(x);
}
}
#endif
#if defined(isinf)
#undef isinf
namespace std {
bool isinf(double x) {
return _isinf(x);
}
}
#endif
#endif
using icu::number::impl::DecimalQuantity;
using namespace icu::number;
//#define NUMFMTST_CACHE_DEBUG 1
#include "stdio.h" /* for sprintf */
// #include "iostream" // for cout
//#define NUMFMTST_DEBUG 1
static const UChar EUR[] = {69,85,82,0}; // "EUR"
static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD"
// *****************************************************************************
// class NumberFormatTest
// *****************************************************************************
#define CHECK(status,str) UPRV_BLOCK_MACRO_BEGIN { \
if (U_FAILURE(status)) { \
errcheckln(status, UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); \
return; \
} \
} UPRV_BLOCK_MACRO_END
#define CHECK_DATA(status,str) UPRV_BLOCK_MACRO_BEGIN { \
if (U_FAILURE(status)) { \
dataerrln(UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); \
return; \
} \
} UPRV_BLOCK_MACRO_END
void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(TestCurrencySign);
TESTCASE_AUTO(TestCurrency);
TESTCASE_AUTO(TestParse);
TESTCASE_AUTO(TestRounding487);
TESTCASE_AUTO(TestQuotes);
TESTCASE_AUTO(TestExponential);
TESTCASE_AUTO(TestPatterns);
TESTCASE_AUTO(Test20186_SpacesAroundSemicolon);
// Upgrade to alphaWorks - liu 5/99
TESTCASE_AUTO(TestExponent);
TESTCASE_AUTO(TestScientific);
TESTCASE_AUTO(TestPad);
TESTCASE_AUTO(TestPatterns2);
TESTCASE_AUTO(TestSecondaryGrouping);
TESTCASE_AUTO(TestSurrogateSupport);
TESTCASE_AUTO(TestAPI);
TESTCASE_AUTO(TestCurrencyObject);
TESTCASE_AUTO(TestCurrencyPatterns);
//TESTCASE_AUTO(TestDigitList);
TESTCASE_AUTO(TestWhiteSpaceParsing);
TESTCASE_AUTO(TestComplexCurrency); // This test removed because CLDR no longer uses choice formats in currency symbols.
TESTCASE_AUTO(TestRegCurrency);
TESTCASE_AUTO(TestSymbolsWithBadLocale);
TESTCASE_AUTO(TestAdoptDecimalFormatSymbols);
TESTCASE_AUTO(TestScientific2);
TESTCASE_AUTO(TestScientificGrouping);
TESTCASE_AUTO(TestInt64);
TESTCASE_AUTO(TestPerMill);
TESTCASE_AUTO(TestIllegalPatterns);
TESTCASE_AUTO(TestCases);
TESTCASE_AUTO(TestCurrencyNames);
TESTCASE_AUTO(Test20484_NarrowSymbolFallback);
TESTCASE_AUTO(TestCurrencyAmount);
TESTCASE_AUTO(TestCurrencyUnit);
TESTCASE_AUTO(TestCoverage);
TESTCASE_AUTO(TestLocalizedPatternSymbolCoverage);
TESTCASE_AUTO(TestJB3832);
TESTCASE_AUTO(TestHost);
TESTCASE_AUTO(TestHostClone);
TESTCASE_AUTO(TestCurrencyFormat);
TESTCASE_AUTO(TestRounding);
TESTCASE_AUTO(TestNonpositiveMultiplier);
TESTCASE_AUTO(TestNumberingSystems);
TESTCASE_AUTO(TestSpaceParsing);
TESTCASE_AUTO(TestMultiCurrencySign);
TESTCASE_AUTO(TestCurrencyFormatForMixParsing);
TESTCASE_AUTO(TestMismatchedCurrencyFormatFail);
TESTCASE_AUTO(TestDecimalFormatCurrencyParse);
TESTCASE_AUTO(TestCurrencyIsoPluralFormat);
TESTCASE_AUTO(TestCurrencyParsing);
TESTCASE_AUTO(TestParseCurrencyInUCurr);
TESTCASE_AUTO(TestFormatAttributes);
TESTCASE_AUTO(TestFieldPositionIterator);
TESTCASE_AUTO(TestDecimal);
TESTCASE_AUTO(TestCurrencyFractionDigits);
TESTCASE_AUTO(TestExponentParse);
TESTCASE_AUTO(TestExplicitParents);
TESTCASE_AUTO(TestLenientParse);
TESTCASE_AUTO(TestAvailableNumberingSystems);
TESTCASE_AUTO(TestRoundingPattern);
TESTCASE_AUTO(Test9087);
TESTCASE_AUTO(TestFormatFastpaths);
TESTCASE_AUTO(TestFormattableSize);
TESTCASE_AUTO(TestUFormattable);
TESTCASE_AUTO(TestSignificantDigits);
TESTCASE_AUTO(TestShowZero);
TESTCASE_AUTO(TestCompatibleCurrencies);
TESTCASE_AUTO(TestBug9936);
TESTCASE_AUTO(TestParseNegativeWithFaLocale);
TESTCASE_AUTO(TestParseNegativeWithAlternateMinusSign);
TESTCASE_AUTO(TestCustomCurrencySignAndSeparator);
TESTCASE_AUTO(TestParseSignsAndMarks);
TESTCASE_AUTO(Test10419RoundingWith0FractionDigits);
TESTCASE_AUTO(Test10468ApplyPattern);
TESTCASE_AUTO(TestRoundingScientific10542);
TESTCASE_AUTO(TestZeroScientific10547);
TESTCASE_AUTO(TestAccountingCurrency);
TESTCASE_AUTO(TestCurrencyFormatForMissingLocale);
TESTCASE_AUTO(TestEquality);
TESTCASE_AUTO(TestCurrencyUsage);
TESTCASE_AUTO(TestDoubleLimit11439);
TESTCASE_AUTO(TestGetAffixes);
TESTCASE_AUTO(TestToPatternScientific11648);
TESTCASE_AUTO(TestBenchmark);
TESTCASE_AUTO(TestCtorApplyPatternDifference);
TESTCASE_AUTO(TestFractionalDigitsForCurrency);
TESTCASE_AUTO(TestFormatCurrencyPlural);
TESTCASE_AUTO(Test11868);
TESTCASE_AUTO(Test11739_ParseLongCurrency);
TESTCASE_AUTO(Test13035_MultiCodePointPaddingInPattern);
TESTCASE_AUTO(Test13737_ParseScientificStrict);
TESTCASE_AUTO(Test10727_RoundingZero);
TESTCASE_AUTO(Test11376_getAndSetPositivePrefix);
TESTCASE_AUTO(Test11475_signRecognition);
TESTCASE_AUTO(Test11640_getAffixes);
TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency);
TESTCASE_AUTO(Test13327_numberingSystemBufferOverflow);
TESTCASE_AUTO(Test13391_chakmaParsing);
TESTCASE_AUTO(Test11735_ExceptionIssue);
TESTCASE_AUTO(Test11035_FormatCurrencyAmount);
TESTCASE_AUTO(Test11318_DoubleConversion);
TESTCASE_AUTO(TestParsePercentRegression);
TESTCASE_AUTO(TestMultiplierWithScale);
TESTCASE_AUTO(TestFastFormatInt32);
TESTCASE_AUTO(Test11646_Equality);
TESTCASE_AUTO(TestParseNaN);
TESTCASE_AUTO(TestFormatFailIfMoreThanMaxDigits);
TESTCASE_AUTO(TestParseCaseSensitive);
TESTCASE_AUTO(TestParseNoExponent);
TESTCASE_AUTO(TestSignAlwaysShown);
TESTCASE_AUTO(TestMinimumGroupingDigits);
TESTCASE_AUTO(Test11897_LocalizedPatternSeparator);
TESTCASE_AUTO(Test13055_PercentageRounding);
TESTCASE_AUTO(Test11839);
TESTCASE_AUTO(Test10354);
TESTCASE_AUTO(Test11645_ApplyPatternEquality);
TESTCASE_AUTO(Test12567);
TESTCASE_AUTO(Test11626_CustomizeCurrencyPluralInfo);
TESTCASE_AUTO(Test20073_StrictPercentParseErrorIndex);
TESTCASE_AUTO(Test13056_GroupingSize);
TESTCASE_AUTO(Test11025_CurrencyPadding);
TESTCASE_AUTO(Test11648_ExpDecFormatMalPattern);
TESTCASE_AUTO(Test11649_DecFmtCurrencies);
TESTCASE_AUTO(Test13148_ParseGroupingSeparators);
TESTCASE_AUTO(Test12753_PatternDecimalPoint);
TESTCASE_AUTO(Test11647_PatternCurrencySymbols);
TESTCASE_AUTO(Test11913_BigDecimal);
TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
TESTCASE_AUTO(Test13777_ParseLongNameNonCurrencyMode);
TESTCASE_AUTO(Test13804_EmptyStringsWhenParsing);
TESTCASE_AUTO(Test20037_ScientificIntegerOverflow);
TESTCASE_AUTO(Test13840_ParseLongStringCrash);
TESTCASE_AUTO(Test13850_EmptyStringCurrency);
TESTCASE_AUTO(Test20348_CurrencyPrefixOverride);
TESTCASE_AUTO(Test20358_GroupingInPattern);
TESTCASE_AUTO(Test13731_DefaultCurrency);
TESTCASE_AUTO(Test20499_CurrencyVisibleDigitsPlural);
TESTCASE_AUTO_END;
}
// -------------------------------------
// Test API (increase code coverage)
void
NumberFormatTest::TestAPI(void)
{
logln("Test API");
UErrorCode status = U_ZERO_ERROR;
NumberFormat *test = NumberFormat::createInstance("root", status);
if(U_FAILURE(status)) {
dataerrln("unable to create format object - %s", u_errorName(status));
}
if(test != NULL) {
test->setMinimumIntegerDigits(10);
test->setMaximumIntegerDigits(1);
test->setMinimumFractionDigits(10);
test->setMaximumFractionDigits(1);
UnicodeString result;
FieldPosition pos;
Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers
test->format(bla, result, pos, status);
if(U_SUCCESS(status)) {
errln("Yuck... Formatted a duck... As a number!");
} else {
status = U_ZERO_ERROR;
}
result.remove();
int64_t ll = 12;
test->format(ll, result);
assertEquals("format int64_t error", u"2.0", result);
test->setMinimumIntegerDigits(4);
test->setMinimumFractionDigits(4);
result.remove();
test->format(ll, result);
assertEquals("format int64_t error", u"0,012.0000", result);
ParsePosition ppos;
LocalPointer<CurrencyAmount> currAmt(test->parseCurrency("",ppos));
// old test for (U_FAILURE(status)) was bogus here, method does not set status!
if (ppos.getIndex()) {
errln("Parsed empty string as currency");
}
delete test;
}
}
class StubNumberFormat :public NumberFormat{
public:
StubNumberFormat(){}
virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const {
return appendTo;
}
virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const {
return appendTo.append((UChar)0x0033);
}
virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const {
return NumberFormat::format(number, appendTo, pos);
}
virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const {
return appendTo;
}
virtual void parse(const UnicodeString& ,
Formattable& ,
ParsePosition& ) const {}
virtual void parse( const UnicodeString& ,
Formattable& ,
UErrorCode& ) const {}
virtual UClassID getDynamicClassID(void) const {
static char classID = 0;
return (UClassID)&classID;
}
virtual StubNumberFormat* clone() const {return NULL;}
};
void
NumberFormatTest::TestCoverage(void){
StubNumberFormat stub;
UnicodeString agent("agent");
FieldPosition pos;
int64_t num = 4;
if (stub.format(num, agent, pos) != UnicodeString("agent3")){
errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)");
}
}
void NumberFormatTest::TestLocalizedPatternSymbolCoverage() {
IcuTestErrorCode errorCode(*this, "TestLocalizedPatternSymbolCoverage");
// Ticket #12961: DecimalFormat::toLocalizedPattern() is not working as designed.
DecimalFormatSymbols dfs(errorCode);
dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u'⁖');
dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'⁘');
dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u'⁙');
dfs.setSymbol(DecimalFormatSymbols::kDigitSymbol, u'▰');
dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u'໐');
dfs.setSymbol(DecimalFormatSymbols::kSignificantDigitSymbol, u'⁕');
dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u'†');
dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u'‡');
dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u'⁜');
dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u'‱');
dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"⁑⁑"); // tests multi-char sequence
dfs.setSymbol(DecimalFormatSymbols::kPadEscapeSymbol, u'⁂');
{
UnicodeString standardPattern(u"#,##0.05+%;#,##0.05-%");
UnicodeString localizedPattern(u"▰⁖▰▰໐⁘໐໕†⁜⁙▰⁖▰▰໐⁘໐໕‡⁜");
DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
df1.applyPattern(standardPattern, errorCode);
DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
df2.applyLocalizedPattern(localizedPattern, errorCode);
assertTrue("DecimalFormat instances should be equal", df1 == df2);
UnicodeString p2;
assertEquals("toPattern should match on localizedPattern instance",
standardPattern, df2.toPattern(p2));
UnicodeString lp1;
assertEquals("toLocalizedPattern should match on standardPattern instance",
localizedPattern, df1.toLocalizedPattern(lp1));
}
{
UnicodeString standardPattern(u"* @@@E0‰");
UnicodeString localizedPattern(u"⁂ ⁕⁕⁕⁑⁑໐‱");
DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
df1.applyPattern(standardPattern, errorCode);
DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
df2.applyLocalizedPattern(localizedPattern, errorCode);
assertTrue("DecimalFormat instances should be equal", df1 == df2);
UnicodeString p2;
assertEquals("toPattern should match on localizedPattern instance",
standardPattern, df2.toPattern(p2));
UnicodeString lp1;
assertEquals("toLocalizedPattern should match on standardPattern instance",
localizedPattern, df1.toLocalizedPattern(lp1));
}
}
// Test various patterns
void
NumberFormatTest::TestPatterns(void)
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols sym(Locale::getUS(), status);
if (U_FAILURE(status)) { errcheckln(status, "FAIL: Could not construct DecimalFormatSymbols - %s", u_errorName(status)); return; }
const char* pat[] = { "#.#", "#.", ".#", "#" };
int32_t pat_length = UPRV_LENGTHOF(pat);
const char* newpat[] = { "0.#", "0.", "#.0", "0" };
const char* num[] = { "0", "0.", ".0", "0" };
for (int32_t i=0; i<pat_length; ++i)
{
status = U_ZERO_ERROR;
DecimalFormat fmt(pat[i], sym, status);
if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; }
UnicodeString newp; fmt.toPattern(newp);
if (!(newp == newpat[i]))
errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
"; " + newp + " seen instead");
UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s);
if (!(s == num[i]))
{
errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
"; " + s + " seen instead");
logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits());
}
}
}
void NumberFormatTest::Test20186_SpacesAroundSemicolon() {
IcuTestErrorCode status(*this, "Test20186_SpacesAroundSemicolon");
DecimalFormat df(u"0.00 ; -0.00", {"en-us", status}, status);
expect2(df, 1, u"1.00 ");
expect2(df, -1, u" -1.00");
df = DecimalFormat(u"0.00;", {"en-us", status}, status);
expect2(df, 1, u"1.00");
expect2(df, -1, u"-1.00");
df = DecimalFormat(u"0.00;0.00", {"en-us", status}, status);
expect2(df, 1, u"1.00");
expect(df, -1, u"1.00"); // parses as 1, not -1
df = DecimalFormat(u" 0.00 ; -0.00 ", {"en-us", status}, status);
expect2(df, 1, u" 1.00 ");
expect2(df, -1, u" -1.00 ");
}
/*
icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
*/
/*
void
NumberFormatTest::TestDigitList(void)
{
// API coverage for DigitList
DigitList list1;
list1.append('1');
list1.fDecimalAt = 1;
DigitList list2;
list2.set((int32_t)1);
if (list1 != list2) {
errln("digitlist append, operator!= or set failed ");
}
if (!(list1 == list2)) {
errln("digitlist append, operator== or set failed ");
}
}
*/
// -------------------------------------
// Test exponential pattern
void
NumberFormatTest::TestExponential(void)
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols sym(Locale::getUS(), status);
if (U_FAILURE(status)) { errcheckln(status, "FAIL: Bad status returned by DecimalFormatSymbols ct - %s", u_errorName(status)); return; }
const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
int32_t pat_length = UPRV_LENGTHOF(pat);
// The following #if statements allow this test to be built and run on
// platforms that do not have standard IEEE numerics. For example,
// S/390 doubles have an exponent range of -78 to +75. For the
// following #if statements to work, float.h must define
// DBL_MAX_10_EXP to be a compile-time constant.
// This section may be expanded as needed.
#if DBL_MAX_10_EXP > 300
double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
int32_t val_length = UPRV_LENGTHOF(val);
const char* valFormat[] =
{
// 0.####E0
"1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
// 00.000E00
"12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
// ##0.######E000
"12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
// 0.###E0;[0.###E0]
"1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]"
};
double valParse[] =
{
0.01234, 123460000, 1.23E300, -3.1416E-271,
0.01234, 123460000, 1.23E300, -3.1416E-271,
0.01234, 123456800, 1.23E300, -3.141593E-271,
0.01234, 123500000, 1.23E300, -3.142E-271,
};
#elif DBL_MAX_10_EXP > 70
double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 };
int32_t val_length = UPRV_LENGTHOF(val);
char* valFormat[] =
{
// 0.####E0
"1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71",
// 00.000E00
"12.340E-03", "12.346E07", "12.300E69", "-31.416E-72",
// ##0.######E000
"12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072",
// 0.###E0;[0.###E0]
"1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]"
};
double valParse[] =
{
0.01234, 123460000, 1.23E70, -3.1416E-71,
0.01234, 123460000, 1.23E70, -3.1416E-71,
0.01234, 123456800, 1.23E70, -3.141593E-71,
0.01234, 123500000, 1.23E70, -3.142E-71,
};
#else
// Don't test double conversion
double* val = 0;
int32_t val_length = 0;
char** valFormat = 0;
double* valParse = 0;
logln("Warning: Skipping double conversion tests");
#endif
int32_t lval[] = { 0, -1, 1, 123456789 };
int32_t lval_length = UPRV_LENGTHOF(lval);
const char* lvalFormat[] =
{
// 0.####E0
"0E0", "-1E0", "1E0", "1.2346E8",
// 00.000E00
"00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
// ##0.######E000
"0E000", "-1E000", "1E000", "123.4568E006",
// 0.###E0;[0.###E0]
"0E0", "[1E0]", "1E0", "1.235E8"
};
int32_t lvalParse[] =
{
0, -1, 1, 123460000,
0, -1, 1, 123460000,
0, -1, 1, 123456800,
0, -1, 1, 123500000,
};
int32_t ival = 0, ilval = 0;
for (int32_t p=0; p<pat_length; ++p)
{
DecimalFormat fmt(pat[p], sym, status);
if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; }
UnicodeString pattern;
logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" +
fmt.toPattern(pattern) + "\"");
int32_t v;
for (v=0; v<val_length; ++v)
{
UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s);
logln((UnicodeString)" " + val[v] + " -format-> " + s);
if (s != valFormat[v+ival])
errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]);
ParsePosition pos(0);
Formattable af;
fmt.parse(s, af, pos);
double a;
UBool useEpsilon = FALSE;
if (af.getType() == Formattable::kLong)
a = af.getLong();
else if (af.getType() == Formattable::kDouble) {
a = af.getDouble();
#if U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400
// S/390 will show a failure like this:
//| -3.141592652999999e-271 -format-> -3.1416E-271
//| -parse-> -3.1416e-271
//| FAIL: Expected -3.141599999999999e-271
// To compensate, we use an epsilon-based equality
// test on S/390 only. We don't want to do this in
// general because it's less exacting.
useEpsilon = TRUE;
#endif
}
else {
errln(UnicodeString("FAIL: Non-numeric Formattable returned: ") + pattern + " " + s);
continue;
}
if (pos.getIndex() == s.length())
{
logln((UnicodeString)" -parse-> " + a);
// Use epsilon comparison as necessary
if ((useEpsilon &&
(uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
(!useEpsilon && a != valParse[v+ival]))
{
errln((UnicodeString)"FAIL: Expected " + valParse[v+ival] + " but got " + a
+ " on input " + s);
}
}
else {
errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
errln((UnicodeString)" should be (" + s.length() + " chars) -> " + valParse[v+ival]);
}
}
for (v=0; v<lval_length; ++v)
{
UnicodeString s;
(*(NumberFormat*)&fmt).format(lval[v], s);
logln((UnicodeString)" " + lval[v] + "L -format-> " + s);
if (s != lvalFormat[v+ilval])
errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s);
ParsePosition pos(0);
Formattable af;
fmt.parse(s, af, pos);
if (af.getType() == Formattable::kLong ||
af.getType() == Formattable::kInt64) {
UErrorCode status = U_ZERO_ERROR;
int32_t a = af.getLong(status);
if (pos.getIndex() == s.length())
{
logln((UnicodeString)" -parse-> " + a);
if (a != lvalParse[v+ilval])
errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval] + " but got " + a);
}
else
errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
}
else
errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s
+ " Double: " + af.getDouble()
+ ", Long: " + af.getLong());
}
ival += val_length;
ilval += lval_length;
}
}
void
NumberFormatTest::TestScientific2() {
// jb 2552
UErrorCode status = U_ZERO_ERROR;
DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
if (U_SUCCESS(status)) {
double num = 12.34;
expect(*fmt, num, "$12.34");
fmt->setScientificNotation(TRUE);
expect(*fmt, num, "$1.23E1");
fmt->setScientificNotation(FALSE);
expect(*fmt, num, "$12.34");
}
delete fmt;
}
void
NumberFormatTest::TestScientificGrouping() {
// jb 2552
UErrorCode status = U_ZERO_ERROR;
DecimalFormat fmt("##0.00E0",status);
if (assertSuccess("", status, true, __FILE__, __LINE__)) {
expect(fmt, .01234, "12.3E-3");
expect(fmt, .1234, "123E-3");
expect(fmt, 1.234, "1.23E0");
expect(fmt, 12.34, "12.3E0");
expect(fmt, 123.4, "123E0");
expect(fmt, 1234., "1.23E3");
}
}
/*static void setFromString(DigitList& dl, const char* str) {
char c;
UBool decimalSet = FALSE;
dl.clear();
while ((c = *str++)) {
if (c == '-') {
dl.fIsPositive = FALSE;
} else if (c == '+') {
dl.fIsPositive = TRUE;
} else if (c == '.') {
dl.fDecimalAt = dl.fCount;
decimalSet = TRUE;
} else {
dl.append(c);
}
}
if (!decimalSet) {
dl.fDecimalAt = dl.fCount;
}
}*/
void
NumberFormatTest::TestInt64() {
UErrorCode status = U_ZERO_ERROR;
DecimalFormat fmt("#.#E0",status);
if (U_FAILURE(status)) {
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
return;
}
fmt.setMaximumFractionDigits(20);
if (U_SUCCESS(status)) {
expect(fmt, (Formattable)(int64_t)0, "0E0");
expect(fmt, (Formattable)(int64_t)-1, "-1E0");
expect(fmt, (Formattable)(int64_t)1, "1E0");
expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9");
expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9");
expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18");
expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18");
}
// also test digitlist
/* int64_t int64max = U_INT64_MAX;
int64_t int64min = U_INT64_MIN;
const char* int64maxstr = "9223372036854775807";
const char* int64minstr = "-9223372036854775808";
UnicodeString fail("fail: ");
// test max int64 value
DigitList dl;
setFromString(dl, int64maxstr);
{
if (!dl.fitsIntoInt64(FALSE)) {
errln(fail + int64maxstr + " didn't fit");
}
int64_t int64Value = dl.getInt64();
if (int64Value != int64max) {
errln(fail + int64maxstr);
}
dl.set(int64Value);
int64Value = dl.getInt64();
if (int64Value != int64max) {
errln(fail + int64maxstr);
}
}
// test negative of max int64 value (1 shy of min int64 value)
dl.fIsPositive = FALSE;
{
if (!dl.fitsIntoInt64(FALSE)) {
errln(fail + "-" + int64maxstr + " didn't fit");
}
int64_t int64Value = dl.getInt64();
if (int64Value != -int64max) {
errln(fail + "-" + int64maxstr);
}
dl.set(int64Value);
int64Value = dl.getInt64();
if (int64Value != -int64max) {
errln(fail + "-" + int64maxstr);
}
}
// test min int64 value
setFromString(dl, int64minstr);
{
if (!dl.fitsIntoInt64(FALSE)) {
errln(fail + "-" + int64minstr + " didn't fit");
}
int64_t int64Value = dl.getInt64();
if (int64Value != int64min) {
errln(fail + int64minstr);
}
dl.set(int64Value);
int64Value = dl.getInt64();
if (int64Value != int64min) {
errln(fail + int64minstr);
}
}
// test negative of min int 64 value (1 more than max int64 value)
dl.fIsPositive = TRUE; // won't fit
{
if (dl.fitsIntoInt64(FALSE)) {
errln(fail + "-(" + int64minstr + ") didn't fit");
}
}*/
}
// -------------------------------------
// Test the handling of quotes
void
NumberFormatTest::TestQuotes(void)
{
UErrorCode status = U_ZERO_ERROR;
UnicodeString *pat;
DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status);
if (U_FAILURE(status)) {
errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status));
delete sym;
return;
}
pat = new UnicodeString("a'fo''o'b#");
DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status);
UnicodeString s;
((NumberFormat*)fmt)->format((int32_t)123, s);
logln((UnicodeString)"Pattern \"" + *pat + "\"");
logln((UnicodeString)" Format 123 -> " + escape(s));
if (!(s=="afo'ob123"))
errln((UnicodeString)"FAIL: Expected afo'ob123");
s.truncate(0);
delete fmt;
delete pat;
pat = new UnicodeString("a''b#");
fmt = new DecimalFormat(*pat, *sym, status);
((NumberFormat*)fmt)->format((int32_t)123, s);
logln((UnicodeString)"Pattern \"" + *pat + "\"");
logln((UnicodeString)" Format 123 -> " + escape(s));
if (!(s=="a'b123"))
errln((UnicodeString)"FAIL: Expected a'b123");
delete fmt;
delete pat;
delete sym;
}
/**
* Test the handling of the currency symbol in patterns.
*/
void
NumberFormatTest::TestCurrencySign(void)
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status);
UnicodeString pat;
UChar currency = 0x00A4;
if (U_FAILURE(status)) {
errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status));
delete sym;
return;
}
// "\xA4#,##0.00;-\xA4#,##0.00"
pat.append(currency).append("#,##0.00;-").
append(currency).append("#,##0.00");
DecimalFormat *fmt = new DecimalFormat(pat, *sym, status);
UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s);
pat.truncate(0);
logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
if (s != "$1,234.56") dataerrln((UnicodeString)"FAIL: Expected $1,234.56");
s.truncate(0);
((NumberFormat*)fmt)->format(- 1234.56, s);
logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
if (s != "-$1,234.56") dataerrln((UnicodeString)"FAIL: Expected -$1,234.56");
delete fmt;
pat.truncate(0);
// "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
pat.append(currency).append(currency).
append(" #,##0.00;").
append(currency).append(currency).
append(" -#,##0.00");
fmt = new DecimalFormat(pat, *sym, status);
s.truncate(0);
((NumberFormat*)fmt)->format(1234.56, s);
logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
if (s != "USD 1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD 1,234.56");
s.truncate(0);
((NumberFormat*)fmt)->format(-1234.56, s);
logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
if (s != "USD -1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD -1,234.56");
delete fmt;
delete sym;
if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + u_errorName(status));
}
// -------------------------------------
static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
UnicodeString&
NumberFormatTest::escape(UnicodeString& s)
{
UnicodeString buf;
for (int32_t i=0; i<s.length(); ++i)
{
UChar c = s[(int32_t)i];
if (c <= (UChar)0x7F) buf += c;
else {
buf += (UChar)0x5c; buf += (UChar)0x55;
buf += toHexString((c & 0xF000) >> 12);
buf += toHexString((c & 0x0F00) >> 8);
buf += toHexString((c & 0x00F0) >> 4);
buf += toHexString(c & 0x000F);
}
}
return (s = buf);
}
// -------------------------------------
static const char* testCases[][2]= {
/* locale ID */ /* expected */
{"ca_ES@currency=ESP", "\\u20A7\\u00A01.150" },
{"de_LU@currency=LUF", "1,150\\u00A0F" },
{"el_GR@currency=GRD", "1.150,50\\u00A0\\u0394\\u03C1\\u03C7" },
{"en_BE@currency=BEF", "1.150,50\\u00A0BEF" },
{"es_ES@currency=ESP", "1.150\\u00A0\\u20A7" },
{"eu_ES@currency=ESP", "\\u20A7\\u00A01.150" },
{"gl_ES@currency=ESP", "1.150\\u00A0\\u20A7" },
{"it_IT@currency=ITL", "ITL\\u00A01.150" },
{"pt_PT@currency=PTE", "1,150$50\\u00A0\\u200B"}, // per cldrbug 7670
{"en_US@currency=JPY", "\\u00A51,150"},
{"en_US@currency=jpy", "\\u00A51,150"},
{"en-US-u-cu-jpy", "\\u00A51,150"}
};
/**
* Test localized currency patterns.
*/
void
NumberFormatTest::TestCurrency(void)
{
UErrorCode status = U_ZERO_ERROR;
NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status);
if (U_FAILURE(status)) {
dataerrln("Error calling NumberFormat::createCurrencyInstance()");
return;
}
UnicodeString s; currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre ici a..........." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0$")))
errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$ but got " + s);
delete currencyFmt;
s.truncate(0);
char loc[256]={0};
int len = uloc_canonicalize("de_DE@currency=DEM", loc, 256, &status);
(void)len; // Suppress unused variable warning.
currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status);
currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0DM")))
errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM but got " + s);
delete currencyFmt;
s.truncate(0);
len = uloc_canonicalize("fr_FR@currency=FRF", loc, 256, &status);
currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre en France a....." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0F")))
errln((UnicodeString)"FAIL: Expected 1,50<nbsp>F");
delete currencyFmt;
if (U_FAILURE(status))
errln((UnicodeString)"FAIL: Status " + (int32_t)status);
for(int i=0; i < UPRV_LENGTHOF(testCases); i++){
status = U_ZERO_ERROR;
const char *localeID = testCases[i][0];
UnicodeString expected(testCases[i][1], -1, US_INV);
expected = expected.unescape();
s.truncate(0);
char loc[256]={0};
uloc_canonicalize(localeID, loc, 256, &status);
currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
if(U_FAILURE(status)){
errln("Could not create currency formatter for locale %s",localeID);
continue;
}
currencyFmt->format(1150.50, s);
if(s!=expected){
errln(UnicodeString("FAIL: Expected: ")+expected
+ UnicodeString(" Got: ") + s
+ UnicodeString( " for locale: ")+ UnicodeString(localeID) );
}
if (U_FAILURE(status)){
errln((UnicodeString)"FAIL: Status " + (int32_t)status);
}
delete currencyFmt;
}
}
// -------------------------------------
/**
* Test the Currency object handling, new as of ICU 2.2.
*/
void NumberFormatTest::TestCurrencyObject() {
UErrorCode ec = U_ZERO_ERROR;
NumberFormat* fmt =
NumberFormat::createCurrencyInstance(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
dataerrln("FAIL: getCurrencyInstance(US) - %s", u_errorName(ec));
delete fmt;
return;
}
Locale null("", "", "");
expectCurrency(*fmt, null, 1234.56, "$1,234.56");
expectCurrency(*fmt, Locale::getFrance(),
1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro
expectCurrency(*fmt, Locale::getJapan(),
1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
expectCurrency(*fmt, Locale("fr", "CH", ""),
1234.56, "CHF 1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
expectCurrency(*fmt, Locale::getUS(),
1234.56, "$1,234.56");
delete fmt;
fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec);
if (U_FAILURE(ec)) {
errln("FAIL: getCurrencyInstance(FRANCE)");
delete fmt;
return;
}
expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1\\u202F234,56 \\u20AC"));
expectCurrency(*fmt, Locale::getJapan(),
1234.56, CharsToUnicodeString("1\\u202F235 JPY")); // Yen
expectCurrency(*fmt, Locale("fr", "CH", ""),
1234.56, CharsToUnicodeString("1\\u202F234,56 CHF")); // no more 0.05 rounding here, see cldrbug 5548
expectCurrency(*fmt, Locale::getUS(),
1234.56, CharsToUnicodeString("1\\u202F234,56 $US"));
expectCurrency(*fmt, Locale::getFrance(),
1234.56, CharsToUnicodeString("1\\u202F234,56 \\u20AC")); // Euro
delete fmt;
}
// -------------------------------------
/**
* Do rudimentary testing of parsing.
*/
void
NumberFormatTest::TestParse(void)
{
UErrorCode status = U_ZERO_ERROR;
UnicodeString arg("0");
DecimalFormat* format = new DecimalFormat("00", status);
//try {
Formattable n; format->parse(arg, n, status);
logln((UnicodeString)"parse(" + arg + ") = " + n.getLong());
if (n.getType() != Formattable::kLong ||
n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
delete format;
if (U_FAILURE(status)) errcheckln(status, (UnicodeString)"FAIL: Status " + u_errorName(status));
//}
//catch(Exception e) {
// errln((UnicodeString)"Exception caught: " + e);
//}
}
// -------------------------------------
static const char *lenientAffixTestCases[] = {
"(1)",
"( 1)",
"(1 )",
"( 1 )"
};
static const char *lenientMinusTestCases[] = {
"-5",
"\\u22125",
"\\u27965"
};
static const char *lenientCurrencyTestCases[] = {
"$1,000",
"$ 1,000",
"$1000",
"$ 1000",
"$1 000.00",
"$ 1 000.00",
"$ 1\\u00A0000.00",
"1000.00"
};
// changed from () to - per cldrbug 5674
static const char *lenientNegativeCurrencyTestCases[] = {
"-$1,000",
"-$ 1,000",
"-$1000",
"-$ 1000",
"-$1 000.00",
"-$ 1 000.00",
"- $ 1,000.00 ",
"-$ 1\\u00A0000.00",
"-1000.00"
};
static const char *lenientPercentTestCases[] = {
"25%",
" 25%",
" 25 %",
"25 %",
"25\\u00A0%",
"25"
};
static const char *lenientNegativePercentTestCases[] = {
"-25%",
" -25%",
" - 25%",
"- 25 %",
" - 25 %",
"-25 %",
"-25\\u00A0%",
"-25",
"- 25"
};
static const char *strictFailureTestCases[] = {
" 1000",
"10,00",
"1,000,.0"
};
/**
* Test lenient parsing.
*/
void
NumberFormatTest::TestLenientParse(void)
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormat *format = new DecimalFormat("(#,##0)", status);
Formattable n;
if (format == NULL || U_FAILURE(status)) {
dataerrln("Unable to create DecimalFormat (#,##0) - %s", u_errorName(status));
} else {
format->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF (lenientAffixTestCases); t += 1) {
UnicodeString testCase = ctou(lenientAffixTestCases[t]);
format->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) || n.getType() != Formattable::kLong ||
n.getLong() != 1) {
dataerrln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete format;
}
Locale en_US("en_US");
Locale sv_SE("sv_SE");
NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, UNUM_DECIMAL, status);
if (mFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (sv_SE, UNUM_DECIMAL) - %s", u_errorName(status));
} else {
mFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
UnicodeString testCase = ctou(lenientMinusTestCases[t]);
mFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete mFormat;
}
mFormat = NumberFormat::createInstance(en_US, UNUM_DECIMAL, status);
if (mFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (en_US, UNUM_DECIMAL) - %s", u_errorName(status));
} else {
mFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
UnicodeString testCase = ctou(lenientMinusTestCases[t]);
mFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete mFormat;
}
NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status);
if (cFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (en_US, UNUM_CURRENCY) - %s", u_errorName(status));
} else {
cFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF (lenientCurrencyTestCases); t += 1) {
UnicodeString testCase = ctou(lenientCurrencyTestCases[t]);
cFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != 1000) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativeCurrencyTestCases); t += 1) {
UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]);
cFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != -1000) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete cFormat;
}
NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status);
if (pFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat::createPercentInstance (en_US) - %s", u_errorName(status));
} else {
pFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF (lenientPercentTestCases); t += 1) {
UnicodeString testCase = ctou(lenientPercentTestCases[t]);
pFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());
if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
n.getDouble() != 0.25) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status)
+ "; got: " + n.getDouble(status));
status = U_ZERO_ERROR;
}
}
for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativePercentTestCases); t += 1) {
UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]);
pFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());
if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
n.getDouble() != -0.25) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status)
+ "; got: " + n.getDouble(status));
status = U_ZERO_ERROR;
}
}
delete pFormat;
}
// Test cases that should fail with a strict parse and pass with a
// lenient parse.
NumberFormat *nFormat = NumberFormat::createInstance(en_US, status);
if (nFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (en_US) - %s", u_errorName(status));
} else {
// first, make sure that they fail with a strict parse
for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) {
UnicodeString testCase = ctou(strictFailureTestCases[t]);
nFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (! U_FAILURE(status)) {
errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
}
status = U_ZERO_ERROR;
}
// then, make sure that they pass with a lenient parse
nFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) {
UnicodeString testCase = ctou(strictFailureTestCases[t]);
nFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != 1000) {
errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t]
+ (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete nFormat;
}
}
// -------------------------------------
/**
* Test proper rounding by the format method.
*/
void
NumberFormatTest::TestRounding487(void)
{
UErrorCode status = U_ZERO_ERROR;
NumberFormat *nf = NumberFormat::createInstance(status);
if (U_FAILURE(status)) {
dataerrln("Error calling NumberFormat::createInstance()");
return;
}
roundingTest(*nf, 0.00159999, 4, "0.0016");
roundingTest(*nf, 0.00995, 4, "0.01");
roundingTest(*nf, 12.3995, 3, "12.4");
roundingTest(*nf, 12.4999, 0, "12");
roundingTest(*nf, - 19.5, 0, "-20");
delete nf;
if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
}
/**
* Test the functioning of the secondary grouping value.
*/
void NumberFormatTest::TestSecondaryGrouping(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols ct");
DecimalFormat f("#,##,###", US, status);
CHECK(status, "DecimalFormat ct");
expect2(f, (int32_t)123456789L, "12,34,56,789");
expectPat(f, "#,##,##0");
f.applyPattern("#,###", status);
CHECK(status, "applyPattern");
f.setSecondaryGroupingSize(4);
expect2(f, (int32_t)123456789L, "12,3456,789");
expectPat(f, "#,####,##0");
NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status);
CHECK_DATA(status, "createInstance(hi_IN)");
UnicodeString out;
int32_t l = (int32_t)1876543210L;
g->format(l, out);
delete g;
// expect "1,87,65,43,210", but with Hindi digits
// 01234567890123
UBool ok = TRUE;
if (out.length() != 14) {
ok = FALSE;
} else {
for (int32_t i=0; i<out.length(); ++i) {
UBool expectGroup = FALSE;
switch (i) {
case 1:
case 4:
case 7:
case 10:
expectGroup = TRUE;
break;
}
// Later -- fix this to get the actual grouping
// character from the resource bundle.
UBool isGroup = (out.charAt(i) == 0x002C);
if (isGroup != expectGroup) {
ok = FALSE;
break;
}
}
}
if (!ok) {
errln((UnicodeString)"FAIL Expected " + l +
" x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" +
escape(out) + "\"");
} else {
logln((UnicodeString)"Ok " + l +
" x hi_IN -> \"" +
escape(out) + "\"");
}
}
void NumberFormatTest::TestWhiteSpaceParsing(void) {
UErrorCode ec = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), ec);
DecimalFormat fmt("a b#0c ", US, ec);
if (U_FAILURE(ec)) {
errcheckln(ec, "FAIL: Constructor - %s", u_errorName(ec));
return;
}
// From ICU 62, flexible whitespace needs lenient mode
fmt.setLenient(TRUE);
int32_t n = 1234;
expect(fmt, "a b1234c ", n);
expect(fmt, "a b1234c ", n);
}
/**
* Test currencies whose display name is a ChoiceFormat.
*/
void NumberFormatTest::TestComplexCurrency() {
// UErrorCode ec = U_ZERO_ERROR;
// Locale loc("kn", "IN", "");
// NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
// if (U_SUCCESS(ec)) {
// expect2(*fmt, 1.0, CharsToUnicodeString("Re.\\u00A01.00"));
// Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
// expect(*fmt, 1.00390625, CharsToUnicodeString("Re.\\u00A01.00")); // tricky
// expect2(*fmt, 12345678.0, CharsToUnicodeString("Rs.\\u00A01,23,45,678.00"));
// expect2(*fmt, 0.5, CharsToUnicodeString("Rs.\\u00A00.50"));
// expect2(*fmt, -1.0, CharsToUnicodeString("-Re.\\u00A01.00"));
// expect2(*fmt, -10.0, CharsToUnicodeString("-Rs.\\u00A010.00"));
// } else {
// errln("FAIL: getCurrencyInstance(kn_IN)");
// }
// delete fmt;
}
// -------------------------------------
void
NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected)
{
nf.setMaximumFractionDigits(maxFractionDigits);
UnicodeString out; nf.format(x, out);
logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out);
if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected);
}
/**
* Upgrade to alphaWorks
*/
void NumberFormatTest::TestExponent(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols constructor");
DecimalFormat fmt1(UnicodeString("0.###E0"), US, status);
CHECK(status, "DecimalFormat(0.###E0)");
DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status);
CHECK(status, "DecimalFormat(0.###E+0)");
int32_t n = 1234;
expect2(fmt1, n, "1.234E3");
expect2(fmt2, n, "1.234E+3");
expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
}
/**
* Upgrade to alphaWorks
*/
void NumberFormatTest::TestScientific(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols constructor");
// Test pattern round-trip
const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000",
"0.###E0;[0.###E0]" };
int32_t PAT_length = UPRV_LENGTHOF(PAT);
int32_t DIGITS[] = {
// min int, max int, min frac, max frac
1, 1, 0, 0, // "#E0"
1, 1, 0, 4, // "0.####E0"
2, 2, 3, 3, // "00.000E00"
1, 3, 0, 4, // "##0.####E000"
1, 1, 0, 3, // "0.###E0;[0.###E0]"
};
for (int32_t i=0; i<PAT_length; ++i) {
UnicodeString pat(PAT[i]);
DecimalFormat df(pat, US, status);
CHECK(status, "DecimalFormat constructor");
UnicodeString pat2;
df.toPattern(pat2);
if (pat == pat2) {
logln(UnicodeString("Ok Pattern rt \"") +
pat + "\" -> \"" +
pat2 + "\"");
} else {
errln(UnicodeString("FAIL Pattern rt \"") +
pat + "\" -> \"" +
pat2 + "\"");
}
// Make sure digit counts match what we expect
if (df.getMinimumIntegerDigits() != DIGITS[4*i] ||
df.getMaximumIntegerDigits() != DIGITS[4*i+1] ||
df.getMinimumFractionDigits() != DIGITS[4*i+2] ||
df.getMaximumFractionDigits() != DIGITS[4*i+3]) {
errln(UnicodeString("FAIL \"" + pat +
"\" min/max int; min/max frac = ") +
df.getMinimumIntegerDigits() + "/" +
df.getMaximumIntegerDigits() + ";" +
df.getMinimumFractionDigits() + "/" +
df.getMaximumFractionDigits() + ", expect " +
DIGITS[4*i] + "/" +
DIGITS[4*i+1] + ";" +
DIGITS[4*i+2] + "/" +
DIGITS[4*i+3]);
}
}
// Test the constructor for default locale. We have to
// manually set the default locale, as there is no
// guarantee that the default locale has the same
// scientific format.
Locale def = Locale::getDefault();
Locale::setDefault(Locale::getUS(), status);
expect2(NumberFormat::createScientificInstance(status),
12345.678901,
"1.2345678901E4", status);
Locale::setDefault(def, status);
expect2(new DecimalFormat("#E0", US, status),
12345.0,
"1.2345E4", status);
expect(new DecimalFormat("0E0", US, status),
12345.0,
"1E4", status);
expect2(NumberFormat::createScientificInstance(Locale::getUS(), status),
12345.678901,
"1.2345678901E4", status);
expect(new DecimalFormat("##0.###E0", US, status),
12345.0,
"12.34E3", status);
expect(new DecimalFormat("##0.###E0", US, status),
12345.00001,
"12.35E3", status);
expect2(new DecimalFormat("##0.####E0", US, status),
(int32_t) 12345,
"12.345E3", status);
expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status),
12345.678901,
"1,2345678901E4", status);
expect(new DecimalFormat("##0.####E0", US, status),
789.12345e-9,
"789.12E-9", status);
expect2(new DecimalFormat("##0.####E0", US, status),
780.e-9,
"780E-9", status);
expect(new DecimalFormat(".###E0", US, status),
45678.0,
".457E5", status);
expect2(new DecimalFormat(".###E0", US, status),
(int32_t) 0,
".0E0", status);
/*
expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
new DecimalFormat("##E0", US),
new DecimalFormat("####E0", US),
new DecimalFormat("0E0", US),
new DecimalFormat("00E0", US),
new DecimalFormat("000E0", US),
},
new Long(45678000),
new String[] { "4.5678E7",
"45.678E6",
"4567.8E4",
"5E7",
"46E6",
"457E5",
}
);
!
! Unroll this test into individual tests below...
!
*/
expect2(new DecimalFormat("#E0", US, status),
(int32_t) 45678000, "4.5678E7", status);
expect2(new DecimalFormat("##E0", US, status),
(int32_t) 45678000, "45.678E6", status);
expect2(new DecimalFormat("####E0", US, status),
(int32_t) 45678000, "4567.8E4", status);
expect(new DecimalFormat("0E0", US, status),
(int32_t) 45678000, "5E7", status);
expect(new DecimalFormat("00E0", US, status),
(int32_t) 45678000, "46E6", status);
expect(new DecimalFormat("000E0", US, status),
(int32_t) 45678000, "457E5", status);
/*
expect(new DecimalFormat("###E0", US, status),
new Object[] { new Double(0.0000123), "12.3E-6",
new Double(0.000123), "123E-6",
new Double(0.00123), "1.23E-3",
new Double(0.0123), "12.3E-3",
new Double(0.123), "123E-3",
new Double(1.23), "1.23E0",
new Double(12.3), "12.3E0",
new Double(123), "123E0",
new Double(1230), "1.23E3",
});
!
! Unroll this test into individual tests below...
!
*/
expect2(new DecimalFormat("###E0", US, status),
0.0000123, "12.3E-6", status);
expect2(new DecimalFormat("###E0", US, status),
0.000123, "123E-6", status);
expect2(new DecimalFormat("###E0", US, status),
0.00123, "1.23E-3", status);
expect2(new DecimalFormat("###E0", US, status),
0.0123, "12.3E-3", status);
expect2(new DecimalFormat("###E0", US, status),
0.123, "123E-3", status);
expect2(new DecimalFormat("###E0", US, status),
1.23, "1.23E0", status);
expect2(new DecimalFormat("###E0", US, status),
12.3, "12.3E0", status);
expect2(new DecimalFormat("###E0", US, status),
123.0, "123E0", status);
expect2(new DecimalFormat("###E0", US, status),
1230.0, "1.23E3", status);
/*
expect(new DecimalFormat("0.#E+00", US, status),
new Object[] { new Double(0.00012), "1.2E-04",
new Long(12000), "1.2E+04",
});
!
! Unroll this test into individual tests below...
!
*/
expect2(new DecimalFormat("0.#E+00", US, status),
0.00012, "1.2E-04", status);
expect2(new DecimalFormat("0.#E+00", US, status),
(int32_t) 12000, "1.2E+04", status);
}
/**
* Upgrade to alphaWorks
*/
void NumberFormatTest::TestPad(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols constructor");
expect2(new DecimalFormat("*^##.##", US, status),
int32_t(0), "^^^^0", status);
expect2(new DecimalFormat("*^##.##", US, status),
-1.3, "^-1.3", status);
expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
int32_t(0), "0.0E0______ g-m/s^2", status);
expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
1.0/3, "333.333E-3_ g-m/s^2", status);
expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
int32_t(0), "0.0______ g-m/s^2", status);
expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
1.0/3, "0.33333__ g-m/s^2", status);
// Test padding before a sign
const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
expect2(new DecimalFormat(formatStr, US, status),
int32_t(-10), "xxxxxxxxxx(10.0)", status);
expect2(new DecimalFormat(formatStr, US, status),
int32_t(-1000),"xxxxxxx(1,000.0)", status);
expect2(new DecimalFormat(formatStr, US, status),
int32_t(-1000000),"xxx(1,000,000.0)", status);
expect2(new DecimalFormat(formatStr, US, status),
-100.37, "xxxxxxxx(100.37)", status);
expect2(new DecimalFormat(formatStr, US, status),
-10456.37, "xxxxx(10,456.37)", status);
expect2(new DecimalFormat(formatStr, US, status),
-1120456.37, "xx(1,120,456.37)", status);
expect2(new DecimalFormat(formatStr, US, status),
-112045600.37, "(112,045,600.37)", status);
expect2(new DecimalFormat(formatStr, US, status),
-1252045600.37,"(1,252,045,600.37)", status);
expect2(new DecimalFormat(formatStr, US, status),
int32_t(10), "xxxxxxxxxxxx10.0", status);
expect2(new DecimalFormat(formatStr, US, status),
int32_t(1000),"xxxxxxxxx1,000.0", status);
expect2(new DecimalFormat(formatStr, US, status),
int32_t(1000000),"xxxxx1,000,000.0", status);
expect2(new DecimalFormat(formatStr, US, status),
100.37, "xxxxxxxxxx100.37", status);
expect2(new DecimalFormat(formatStr, US, status),
10456.37, "xxxxxxx10,456.37", status);
expect2(new DecimalFormat(formatStr, US, status),
1120456.37, "xxxx1,120,456.37", status);
expect2(new DecimalFormat(formatStr, US, status),
112045600.37, "xx112,045,600.37", status);
expect2(new DecimalFormat(formatStr, US, status),
10252045600.37,"10,252,045,600.37", status);
// Test padding between a sign and a number
const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(-10), "(10.0xxxxxxxxxx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(-1000),"(1,000.0xxxxxxx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(-1000000),"(1,000,000.0xxx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
-100.37, "(100.37xxxxxxxx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
-10456.37, "(10,456.37xxxxx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
-1120456.37, "(1,120,456.37xx)", status);
expect2(new DecimalFormat(formatStr2, US, status),
-112045600.37, "(112,045,600.37)", status);
expect2(new DecimalFormat(formatStr2, US, status),
-1252045600.37,"(1,252,045,600.37)", status);
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(10), "10.0xxxxxxxxxxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(1000),"1,000.0xxxxxxxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
int32_t(1000000),"1,000,000.0xxxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
100.37, "100.37xxxxxxxxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
10456.37, "10,456.37xxxxxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
1120456.37, "1,120,456.37xxxx", status);
expect2(new DecimalFormat(formatStr2, US, status),
112045600.37, "112,045,600.37xx", status);
expect2(new DecimalFormat(formatStr2, US, status),
10252045600.37,"10,252,045,600.37", status);
//testing the setPadCharacter(UnicodeString) and getPadCharacterString()
DecimalFormat fmt("#", US, status);
CHECK(status, "DecimalFormat constructor");
UnicodeString padString("P");
fmt.setPadCharacter(padString);
expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString);
fmt.setPadCharacter((UnicodeString)"^");
expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^");
//commented untill implementation is complete
/* fmt.setPadCharacter((UnicodeString)"^^^");
expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^");
padString.remove();
padString.append((UChar)0x0061);
padString.append((UChar)0x0302);
fmt.setPadCharacter(padString);
UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
UnicodeString pattern(patternChars);
expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString);
*/
}
/**
* Upgrade to alphaWorks
*/
void NumberFormatTest::TestPatterns2(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols US(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols constructor");
DecimalFormat fmt("#", US, status);
CHECK(status, "DecimalFormat constructor");
UChar hat = 0x005E; /*^*/
expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat);
expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat);
expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat);
expectPad(fmt, "$*^$#", ILLEGAL);
expectPad(fmt, "#$*^$", ILLEGAL);
expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix,
12, (UChar)0x0078 /*x*/);
expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix,
3, (UChar)0x0078 /*x*/);
expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix,
10, (UChar)0x0061 /*a*/);
fmt.applyPattern("AA#,##0.00ZZ", status);
CHECK(status, "applyPattern");
fmt.setPadCharacter(hat);
fmt.setFormatWidth(10);
fmt.setPadPosition(DecimalFormat::kPadBeforePrefix);
expectPat(fmt, "*^AA#,##0.00ZZ");
fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix);
expectPat(fmt, "AA#,##0.00*^ZZ");
fmt.setPadPosition(DecimalFormat::kPadAfterSuffix);
expectPat(fmt, "AA#,##0.00ZZ*^");
// 12 3456789012
UnicodeString exp("AA*^#,##0.00ZZ", "");
fmt.setFormatWidth(12);
fmt.setPadPosition(DecimalFormat::kPadAfterPrefix);
expectPat(fmt, exp);
fmt.setFormatWidth(13);
// 12 34567890123
expectPat(fmt, "AA*^##,##0.00ZZ");
fmt.setFormatWidth(14);
// 12 345678901234
expectPat(fmt, "AA*^###,##0.00ZZ");
fmt.setFormatWidth(15);
// 12 3456789012345
expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
fmt.setFormatWidth(16);
// 12 34567890123456
expectPat(fmt, "AA*^#####,##0.00ZZ");
}
void NumberFormatTest::TestSurrogateSupport(void) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols custom(Locale::getUS(), status);
CHECK(status, "DecimalFormatSymbols constructor");
custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal");
custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus");
custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus ");
custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent");
UnicodeString patternStr("*\\U00010000##.##", "");
patternStr = patternStr.unescape();
UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", "");
expStr = expStr.unescape();
expect2(new DecimalFormat(patternStr, custom, status),
int32_t(0), expStr, status);
status = U_ZERO_ERROR;
expect2(new DecimalFormat("*^##.##", custom, status),
int32_t(0), "^^^^0", status);
status = U_ZERO_ERROR;
expect2(new DecimalFormat("##.##", custom, status),
-1.3, " minus 1decimal3", status);
status = U_ZERO_ERROR;
expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
int32_t(0), "0decimal0exponent0 g-m/s^2", status);
status = U_ZERO_ERROR;
expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
1.0/3, "333decimal333exponent minus 3 g-m/s^2", status);
status = U_ZERO_ERROR;
expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
int32_t(0), "0decimal0 g-m/s^2", status);
status = U_ZERO_ERROR;
expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
1.0/3, "0decimal33333 g-m/s^2", status);
UnicodeString zero((UChar32)0x10000);
UnicodeString one((UChar32)0x10001);
UnicodeString two((UChar32)0x10002);
UnicodeString five((UChar32)0x10005);
custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
custom.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, one);
custom.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, two);
custom.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, five);
expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", "");
expStr = expStr.unescape();
status = U_ZERO_ERROR;
expect2(new DecimalFormat("##0.000", custom, status),
1.25, expStr, status);
custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
patternStr = UNICODE_STRING_SIMPLE("0.00 \\u00A4' in your bank account'");
patternStr = patternStr.unescape();
expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", "");
status = U_ZERO_ERROR;
expect2(new DecimalFormat(patternStr, custom, status),
int32_t(-20), expStr, status);
custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent");
patternStr = "'You''ve lost ' -0.00 %' of your money today'";
patternStr = patternStr.unescape();
expStr = UnicodeString(" minus You've lost minus 2000decimal00 percent of your money today", "");
status = U_ZERO_ERROR;
expect2(new DecimalFormat(patternStr, custom, status),
int32_t(-20), expStr, status);
}
void NumberFormatTest::TestCurrencyPatterns(void) {
int32_t i, locCount;
const Locale* locs = NumberFormat::getAvailableLocales(locCount);
for (i=0; i<locCount; ++i) {
UErrorCode ec = U_ZERO_ERROR;
NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec);
if (U_FAILURE(ec)) {
errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec));
} else {
// Make sure currency formats do not have a variable number
// of fraction digits
int32_t min = nf->getMinimumFractionDigits();
int32_t max = nf->getMaximumFractionDigits();
if (min != max) {
UnicodeString a, b;
nf->format(1.0, a);
nf->format(1.125, b);
errln((UnicodeString)"FAIL: " + locs[i].getName() +
" min fraction digits != max fraction digits; "
"x 1.0 => " + escape(a) +
"; x 1.125 => " + escape(b));
}
// Make sure EURO currency formats have exactly 2 fraction digits
DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
if (df != NULL) {
if (u_strcmp(EUR, df->getCurrency()) == 0) {
if (min != 2 || max != 2) {
UnicodeString a;
nf->format(1.0, a);
errln((UnicodeString)"FAIL: " + locs[i].getName() +
" is a EURO format but it does not have 2 fraction digits; "
"x 1.0 => " +
escape(a));
}
}
}
}
delete nf;
}
}
void NumberFormatTest::TestRegCurrency(void) {
#if !UCONFIG_NO_SERVICE
UErrorCode status = U_ZERO_ERROR;
UChar USD[4];
ucurr_forLocale("en_US", USD, 4, &status);
UChar YEN[4];
ucurr_forLocale("ja_JP", YEN, 4, &status);
UChar TMP[4];
if(U_FAILURE(status)) {
errcheckln(status, "Unable to get currency for locale, error %s", u_errorName(status));
return;
}
UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status);
ucurr_forLocale("en_US", TMP, 4, &status);
if (u_strcmp(YEN, TMP) != 0) {
errln("FAIL: didn't return YEN registered for en_US");
}
int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status);
if (fallbackLen) {
errln("FAIL: tried to fallback en_XX_BAR");
}
status = U_ZERO_ERROR; // reset
if (!ucurr_unregister(enkey, &status)) {
errln("FAIL: couldn't unregister enkey");
}
ucurr_forLocale("en_US", TMP, 4, &status);
if (u_strcmp(USD, TMP) != 0) {
errln("FAIL: didn't return USD for en_US after unregister of en_US");
}
status = U_ZERO_ERROR; // reset
ucurr_forLocale("en_US_BLAH", TMP, 4, &status);
if (u_strcmp(USD, TMP) != 0) {
errln("FAIL: could not find USD for en_US_BLAH after unregister of en");
}
status = U_ZERO_ERROR; // reset
#endif
}
void NumberFormatTest::TestCurrencyNames(void) {
// Do a basic check of getName()
// USD { "US$", "US Dollar" } // 04/04/1792-
UErrorCode ec = U_ZERO_ERROR;
static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/
static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/
static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/
static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/
UBool isChoiceFormat;
int32_t len;
const UBool possibleDataError = TRUE;
// Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK
// THE LOCALE DATA before diving into the code.
assertEquals("USD.getName(SYMBOL_NAME, en)",
UnicodeString("$"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USD.getName(NARROW_SYMBOL_NAME, en)",
UnicodeString("$"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_NARROW_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USD.getName(LONG_NAME, en)",
UnicodeString("US Dollar"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_LONG_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("CAD.getName(SYMBOL_NAME, en)",
UnicodeString("CA$"),
UnicodeString(ucurr_getName(CAD, "en",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("CAD.getName(NARROW_SYMBOL_NAME, en)",
UnicodeString("$"),
UnicodeString(ucurr_getName(CAD, "en",
UCURR_NARROW_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("CAD.getName(SYMBOL_NAME, en_CA)",
UnicodeString("$"),
UnicodeString(ucurr_getName(CAD, "en_CA",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USD.getName(SYMBOL_NAME, en_CA)",
UnicodeString("US$"),
UnicodeString(ucurr_getName(USD, "en_CA",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USD.getName(NARROW_SYMBOL_NAME, en_CA)",
UnicodeString("$"),
UnicodeString(ucurr_getName(USD, "en_CA",
UCURR_NARROW_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USD.getName(SYMBOL_NAME) in en_NZ",
UnicodeString("US$"),
UnicodeString(ucurr_getName(USD, "en_NZ",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("CAD.getName(SYMBOL_NAME)",
UnicodeString("CA$"),
UnicodeString(ucurr_getName(CAD, "en_NZ",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USX.getName(SYMBOL_NAME)",
UnicodeString("USX"),
UnicodeString(ucurr_getName(USX, "en_US",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USX.getName(NARROW_SYMBOL_NAME)",
UnicodeString("USX"),
UnicodeString(ucurr_getName(USX, "en_US",
UCURR_NARROW_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertEquals("USX.getName(LONG_NAME)",
UnicodeString("USX"),
UnicodeString(ucurr_getName(USX, "en_US",
UCURR_LONG_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
assertSuccess("ucurr_getName", ec);
ec = U_ZERO_ERROR;
// Test that a default or fallback warning is being returned. JB 4239.
ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
assertTrue("ucurr_getName (es_ES fallback)",
U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError);
ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
assertTrue("ucurr_getName (zh_TW fallback)",
U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError);
ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
assertTrue("ucurr_getName (en_US default)",
U_USING_DEFAULT_WARNING == ec || U_USING_FALLBACK_WARNING == ec, TRUE);
ucurr_getName(CAD, "ti", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
assertTrue("ucurr_getName (ti default)",
U_USING_DEFAULT_WARNING == ec, TRUE);
// Test that a default warning is being returned when falling back to root. JB 4536.
ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
assertTrue("ucurr_getName (cy default to root)",
U_USING_DEFAULT_WARNING == ec, TRUE);
// TODO add more tests later
}
void NumberFormatTest::Test20484_NarrowSymbolFallback(){
IcuTestErrorCode status(*this, "Test20484_NarrowSymbolFallback");
struct TestCase {
const char* locale;
const char16_t* isoCode;
const char16_t* expectedShort;
const char16_t* expectedNarrow;
UErrorCode expectedNarrowError;
} cases[] = {
{"en-US", u"CAD", u"CA$", u"$", U_USING_DEFAULT_WARNING}, // narrow: fallback to root
{"en-US", u"CDF", u"CDF", u"CDF", U_USING_FALLBACK_WARNING}, // narrow: fallback to short
{"sw-CD", u"CDF", u"FC", u"FC", U_USING_FALLBACK_WARNING}, // narrow: fallback to short
{"en-US", u"GEL", u"GEL", u"₾", U_USING_DEFAULT_WARNING}, // narrow: fallback to root
{"ka-GE", u"GEL", u"₾", u"₾", U_USING_FALLBACK_WARNING}, // narrow: fallback to ka
{"ka", u"GEL", u"₾", u"₾", U_ZERO_ERROR}, // no fallback on narrow
};
for (const auto& cas : cases) {
status.setScope(cas.isoCode);
UBool choiceFormatIgnored;
int32_t lengthIgnored;
const UChar* actualShort = ucurr_getName(
cas.isoCode,
cas.locale,
UCURR_SYMBOL_NAME,
&choiceFormatIgnored,
&lengthIgnored,
status);
status.errIfFailureAndReset();
const UChar* actualNarrow = ucurr_getName(
cas.isoCode,
cas.locale,
UCURR_NARROW_SYMBOL_NAME,
&choiceFormatIgnored,
&lengthIgnored,
status);
status.expectErrorAndReset(cas.expectedNarrowError);
assertEquals(UnicodeString("Short symbol: ") + cas.locale + u": " + cas.isoCode,
cas.expectedShort, actualShort);
assertEquals(UnicodeString("Narrow symbol: ") + cas.locale + ": " + cas.isoCode,
cas.expectedNarrow, actualNarrow);
}
}
void NumberFormatTest::TestCurrencyUnit(void){
UErrorCode ec = U_ZERO_ERROR;
static const UChar USD[] = u"USD";
static const char USD8[] = "USD";
static const UChar BAD[] = u"???";
static const UChar BAD2[] = u"??A";
static const UChar XXX[] = u"XXX";
static const char XXX8[] = "XXX";
static const UChar INV[] = u"{$%";
static const char INV8[] = "{$%";
static const UChar ZZZ[] = u"zz";
static const char ZZZ8[] = "zz";
UChar* EUR = (UChar*) malloc(6);
EUR[0] = u'E';
EUR[1] = u'U';
EUR[2] = u'R';
char* EUR8 = (char*) malloc(3);
EUR8[0] = 'E';
EUR8[1] = 'U';
EUR8[2] = 'R';
CurrencyUnit cu(USD, ec);
assertSuccess("CurrencyUnit", ec);
assertEquals("getISOCurrency()", USD, cu.getISOCurrency());
assertEquals("getSubtype()", USD8, cu.getSubtype());
CurrencyUnit inv(INV, ec);
assertEquals("non-invariant", U_INVARIANT_CONVERSION_ERROR, ec);
assertEquals("non-invariant", XXX, inv.getISOCurrency());
ec = U_ZERO_ERROR;
CurrencyUnit zzz(ZZZ, ec);
assertEquals("too short", U_ILLEGAL_ARGUMENT_ERROR, ec);
assertEquals("too short", XXX, zzz.getISOCurrency());
ec = U_ZERO_ERROR;
CurrencyUnit eur(EUR, ec);
assertEquals("non-nul-terminated", u"EUR", eur.getISOCurrency());
assertEquals("non-nul-terminated", "EUR", eur.getSubtype());
// Test StringPiece constructor
CurrencyUnit cu8(USD8, ec);
assertEquals("StringPiece constructor", USD, cu8.getISOCurrency());
CurrencyUnit inv8(INV8, ec);
assertEquals("non-invariant 8", U_INVARIANT_CONVERSION_ERROR, ec);
assertEquals("non-invariant 8", XXX, inv8.getISOCurrency());
ec = U_ZERO_ERROR;
CurrencyUnit zzz8(ZZZ8, ec);
assertEquals("too short 8", U_ILLEGAL_ARGUMENT_ERROR, ec);
assertEquals("too short 8", XXX, zzz8.getISOCurrency());
ec = U_ZERO_ERROR;
CurrencyUnit zzz8b({ZZZ8, 3}, ec);
assertEquals("too short 8b", U_ILLEGAL_ARGUMENT_ERROR, ec);
assertEquals("too short 8b", XXX, zzz8b.getISOCurrency());
ec = U_ZERO_ERROR;
CurrencyUnit eur8({EUR8, 3}, ec);
assertEquals("non-nul-terminated 8", u"EUR", eur8.getISOCurrency());
assertEquals("non-nul-terminated 8", "EUR", eur8.getSubtype());
CurrencyUnit cu2(cu);
if (!(cu2 == cu)){
errln("CurrencyUnit copy constructed object should be same");
}
CurrencyUnit * cu3 = cu.clone();
if (!(*cu3 == cu)){
errln("CurrencyUnit cloned object should be same");
}
CurrencyUnit bad(BAD, ec);
assertSuccess("CurrencyUnit", ec);
if (cu.getIndex() == bad.getIndex()) {
errln("Indexes of different currencies should differ.");
}
CurrencyUnit bad2(BAD2, ec);
assertSuccess("CurrencyUnit", ec);
if (bad2.getIndex() != bad.getIndex()) {
errln("Indexes of unrecognized currencies should be the same.");
}
if (bad == bad2) {
errln("Different unrecognized currencies should not be equal.");
}
bad = bad2;
if (bad != bad2) {
errln("Currency unit assignment should be the same.");
}
delete cu3;
// Test default constructor
CurrencyUnit def;
assertEquals("Default currency", XXX, def.getISOCurrency());
assertEquals("Default currency as subtype", XXX8, def.getSubtype());
// Test slicing
MeasureUnit sliced1 = cu;
MeasureUnit sliced2 = cu;
assertEquals("Subtype after slicing 1", USD8, sliced1.getSubtype());
assertEquals("Subtype after slicing 2", USD8, sliced2.getSubtype());
CurrencyUnit restored1(sliced1, ec);
CurrencyUnit restored2(sliced2, ec);
assertSuccess("Restoring from MeasureUnit", ec);
assertEquals("Subtype after restoring 1", USD8, restored1.getSubtype());
assertEquals("Subtype after restoring 2", USD8, restored2.getSubtype());
assertEquals("ISO Code after restoring 1", USD, restored1.getISOCurrency());
assertEquals("ISO Code after restoring 2", USD, restored2.getISOCurrency());
// Test copy constructor failure
LocalPointer<MeasureUnit> meter(MeasureUnit::createMeter(ec));
assertSuccess("Creating meter", ec);
CurrencyUnit failure(*meter, ec);
assertEquals("Copying from meter should fail", ec, U_ILLEGAL_ARGUMENT_ERROR);
assertEquals("Copying should not give uninitialized ISO code", u"", failure.getISOCurrency());
free(EUR);
free(EUR8);
}
void NumberFormatTest::TestCurrencyAmount(void){
UErrorCode ec = U_ZERO_ERROR;
static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
CurrencyAmount ca(9, USD, ec);
assertSuccess("CurrencyAmount", ec);
CurrencyAmount ca2(ca);
if (!(ca2 == ca)){
errln("CurrencyAmount copy constructed object should be same");
}
ca2=ca;
if (!(ca2 == ca)){
errln("CurrencyAmount assigned object should be same");
}
CurrencyAmount *ca3 = ca.clone();
if (!(*ca3 == ca)){
errln("CurrencyAmount cloned object should be same");
}
delete ca3;
}
void NumberFormatTest::TestSymbolsWithBadLocale(void) {
Locale locDefault;
static const char *badLocales[] = {
// length < ULOC_FULLNAME_CAPACITY
"x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME",
// length > ULOC_FULLNAME_CAPACITY
"x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME"
}; // expect U_USING_DEFAULT_WARNING for both
unsigned int i;
for (i = 0; i < UPRV_LENGTHOF(badLocales); i++) {
const char *localeName = badLocales[i];
Locale locBad(localeName);
assertTrue(WHERE, !locBad.isBogus());
UErrorCode status = U_ZERO_ERROR;
UnicodeString intlCurrencySymbol((UChar)0xa4);
intlCurrencySymbol.append((UChar)0xa4);
logln("Current locale is %s", Locale::getDefault().getName());
Locale::setDefault(locBad, status);
logln("Current locale is %s", Locale::getDefault().getName());
DecimalFormatSymbols mySymbols(status);
if (status != U_USING_DEFAULT_WARNING) {
errln("DecimalFormatSymbols should return U_USING_DEFAULT_WARNING.");
}
if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
errln("DecimalFormatSymbols does not have the right locale.", locBad.getName());
}
int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
UnicodeString symbolString = mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum);
logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ") + prettify(symbolString));
if (symbolString.length() == 0
&& symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
&& symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
{
errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
}
}
status = U_ZERO_ERROR;
Locale::setDefault(locDefault, status);
logln("Current locale is %s", Locale::getDefault().getName());
}
}
/**
* Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols
* behave the same, except for memory ownership semantics. (No
* version of this test on Java, since Java has only one method.)
*/
void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) {
UErrorCode ec = U_ZERO_ERROR;
DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
errcheckln(ec, "Fail: DecimalFormatSymbols constructor - %s", u_errorName(ec));
delete sym;
return;
}
UnicodeString pat(" #,##0.00");
pat.insert(0, (UChar)0x00A4);
DecimalFormat fmt(pat, sym, ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormat constructor");
return;
}
UnicodeString str;
fmt.format(2350.75, str);
if (str == "$ 2,350.75") {
logln(str);
} else {
dataerrln("Fail: " + str + ", expected $ 2,350.75");
}
sym = new DecimalFormatSymbols(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormatSymbols constructor");
delete sym;
return;
}
sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
fmt.adoptDecimalFormatSymbols(sym);
str.truncate(0);
fmt.format(2350.75, str);
if (str == "Q 2,350.75") {
logln(str);
} else {
dataerrln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
}
sym = new DecimalFormatSymbols(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormatSymbols constructor");
delete sym;
return;
}
DecimalFormat fmt2(pat, sym, ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormat constructor");
return;
}
DecimalFormatSymbols sym2(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormatSymbols constructor");
return;
}
sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
fmt2.setDecimalFormatSymbols(sym2);
str.truncate(0);
fmt2.format(2350.75, str);
if (str == "Q 2,350.75") {
logln(str);
} else {
dataerrln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
}
}
void NumberFormatTest::TestPerMill() {
UErrorCode ec = U_ZERO_ERROR;
UnicodeString str;
DecimalFormat fmt(ctou("###.###\\u2030"), ec);
if (!assertSuccess("DecimalFormat ct", ec)) return;
assertEquals("0.4857 x ###.###\\u2030",
ctou("485.7\\u2030"), fmt.format(0.4857, str), true);
DecimalFormatSymbols sym(Locale::getUS(), ec);
if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
return;
}
sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
DecimalFormat fmt2("", sym, ec);
if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
return;
}
fmt2.applyLocalizedPattern("###.###m", ec);
if (!assertSuccess("setup", ec)) return;
str.truncate(0);
assertEquals("0.4857 x ###.###m",
"485.7m", fmt2.format(0.4857, str));
}
/**
* Generic test for patterns that should be legal/illegal.
*/
void NumberFormatTest::TestIllegalPatterns() {
// Test cases:
// Prefix with "-:" for illegal patterns
// Prefix with "+:" for legal patterns
const char* DATA[] = {
// Unquoted special characters in the suffix are illegal
"-:000.000|###",
"+:000.000'|###'",
0
};
for (int32_t i=0; DATA[i]; ++i) {
const char* pat=DATA[i];
UBool valid = (*pat) == '+';
pat += 2;
UErrorCode ec = U_ZERO_ERROR;
DecimalFormat fmt(pat, ec); // locale doesn't matter here
if (U_SUCCESS(ec) == valid) {
logln("Ok: pattern \"%s\": %s",
pat, u_errorName(ec));
} else {
errcheckln(ec, "FAIL: pattern \"%s\" should have %s; got %s",
pat, (valid?"succeeded":