| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /******************************************************************** |
| * COPYRIGHT: |
| * Copyright (c) 1997-2013, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| ********************************************************************/ |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| |
| #include "unicode/dcfmtsym.h" |
| #include "unicode/decimfmt.h" |
| #include "unicode/unum.h" |
| #include "tsdcfmsy.h" |
| |
| void IntlTestDecimalFormatSymbols::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) |
| { |
| if (exec) { |
| logln("TestSuite DecimalFormatSymbols:"); |
| } |
| TESTCASE_AUTO_BEGIN; |
| TESTCASE_AUTO(testSymbols); |
| TESTCASE_AUTO(testLastResortData); |
| TESTCASE_AUTO(testDigitSymbols); |
| TESTCASE_AUTO(testNumberingSystem); |
| TESTCASE_AUTO_END; |
| } |
| |
| /** |
| * Test the API of DecimalFormatSymbols; primarily a simple get/set set. |
| */ |
| void IntlTestDecimalFormatSymbols::testSymbols(/* char *par */) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| |
| DecimalFormatSymbols fr(Locale::getFrench(), status); |
| if(U_FAILURE(status)) { |
| errcheckln(status, "ERROR: Couldn't create French DecimalFormatSymbols - %s", u_errorName(status)); |
| return; |
| } |
| |
| status = U_ZERO_ERROR; |
| DecimalFormatSymbols en(Locale::getEnglish(), status); |
| if(U_FAILURE(status)) { |
| errcheckln(status, "ERROR: Couldn't create English DecimalFormatSymbols - %s", u_errorName(status)); |
| return; |
| } |
| |
| if(en == fr || ! (en != fr) ) { |
| errln("ERROR: English DecimalFormatSymbols equal to French"); |
| } |
| |
| // just do some VERY basic tests to make sure that get/set work |
| |
| UnicodeString zero = en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero); |
| if(fr.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) { |
| errln("ERROR: get/set ZeroDigit failed"); |
| } |
| |
| UnicodeString group = en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, group); |
| if(fr.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) { |
| errln("ERROR: get/set GroupingSeparator failed"); |
| } |
| |
| UnicodeString decimal = en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, decimal); |
| if(fr.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) { |
| errln("ERROR: get/set DecimalSeparator failed"); |
| } |
| |
| UnicodeString perMill = en.getSymbol(DecimalFormatSymbols::kPerMillSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kPerMillSymbol, perMill); |
| if(fr.getSymbol(DecimalFormatSymbols::kPerMillSymbol) != en.getSymbol(DecimalFormatSymbols::kPerMillSymbol)) { |
| errln("ERROR: get/set PerMill failed"); |
| } |
| |
| UnicodeString percent = en.getSymbol(DecimalFormatSymbols::kPercentSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kPercentSymbol, percent); |
| if(fr.getSymbol(DecimalFormatSymbols::kPercentSymbol) != en.getSymbol(DecimalFormatSymbols::kPercentSymbol)) { |
| errln("ERROR: get/set Percent failed"); |
| } |
| |
| UnicodeString digit(en.getSymbol(DecimalFormatSymbols::kDigitSymbol)); |
| fr.setSymbol(DecimalFormatSymbols::kDigitSymbol, digit); |
| if(fr.getSymbol(DecimalFormatSymbols::kDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kDigitSymbol)) { |
| errln("ERROR: get/set Percent failed"); |
| } |
| |
| UnicodeString patternSeparator = en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, patternSeparator); |
| if(fr.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) { |
| errln("ERROR: get/set PatternSeparator failed"); |
| } |
| |
| UnicodeString infinity(en.getSymbol(DecimalFormatSymbols::kInfinitySymbol)); |
| fr.setSymbol(DecimalFormatSymbols::kInfinitySymbol, infinity); |
| UnicodeString infinity2(fr.getSymbol(DecimalFormatSymbols::kInfinitySymbol)); |
| if(infinity != infinity2) { |
| errln("ERROR: get/set Infinity failed"); |
| } |
| |
| UnicodeString nan(en.getSymbol(DecimalFormatSymbols::kNaNSymbol)); |
| fr.setSymbol(DecimalFormatSymbols::kNaNSymbol, nan); |
| UnicodeString nan2(fr.getSymbol(DecimalFormatSymbols::kNaNSymbol)); |
| if(nan != nan2) { |
| errln("ERROR: get/set NaN failed"); |
| } |
| |
| UnicodeString minusSign = en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
| fr.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, minusSign); |
| if(fr.getSymbol(DecimalFormatSymbols::kMinusSignSymbol) != en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol)) { |
| errln("ERROR: get/set MinusSign failed"); |
| } |
| |
| UnicodeString exponential(en.getSymbol(DecimalFormatSymbols::kExponentialSymbol)); |
| fr.setSymbol(DecimalFormatSymbols::kExponentialSymbol, exponential); |
| if(fr.getSymbol(DecimalFormatSymbols::kExponentialSymbol) != en.getSymbol(DecimalFormatSymbols::kExponentialSymbol)) { |
| errln("ERROR: get/set Exponential failed"); |
| } |
| |
| // Test get currency spacing before the currency. |
| status = U_ZERO_ERROR; |
| for (int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; i++) { |
| UnicodeString enCurrencyPattern = en.getPatternForCurrencySpacing( |
| (UCurrencySpacing)i, TRUE, status); |
| if(U_FAILURE(status)) { |
| errln("Error: cannot get CurrencyMatch for locale:en"); |
| status = U_ZERO_ERROR; |
| } |
| UnicodeString frCurrencyPattern = fr.getPatternForCurrencySpacing( |
| (UCurrencySpacing)i, TRUE, status); |
| if(U_FAILURE(status)) { |
| errln("Error: cannot get CurrencyMatch for locale:fr"); |
| } |
| if (enCurrencyPattern != frCurrencyPattern) { |
| errln("ERROR: get CurrencySpacing failed"); |
| } |
| } |
| // Test get currencySpacing after the currency. |
| status = U_ZERO_ERROR; |
| for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) { |
| UnicodeString enCurrencyPattern = en.getPatternForCurrencySpacing( |
| (UCurrencySpacing)i, FALSE, status); |
| if(U_FAILURE(status)) { |
| errln("Error: cannot get CurrencyMatch for locale:en"); |
| status = U_ZERO_ERROR; |
| } |
| UnicodeString frCurrencyPattern = fr.getPatternForCurrencySpacing( |
| (UCurrencySpacing)i, FALSE, status); |
| if(U_FAILURE(status)) { |
| errln("Error: cannot get CurrencyMatch for locale:fr"); |
| } |
| if (enCurrencyPattern != frCurrencyPattern) { |
| errln("ERROR: get CurrencySpacing failed"); |
| } |
| } |
| // Test set curerncySpacing APIs |
| status = U_ZERO_ERROR; |
| UnicodeString dash = UnicodeString("-"); |
| en.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, dash); |
| UnicodeString enCurrencyInsert = en.getPatternForCurrencySpacing( |
| UNUM_CURRENCY_INSERT, TRUE, status); |
| if (dash != enCurrencyInsert) { |
| errln("Error: Failed to setCurrencyInsert for locale:en"); |
| } |
| |
| status = U_ZERO_ERROR; |
| DecimalFormatSymbols foo(status); |
| |
| DecimalFormatSymbols bar(foo); |
| |
| en = fr; |
| |
| if(en != fr || foo != bar) { |
| errln("ERROR: Copy Constructor or Assignment failed"); |
| } |
| |
| // test get/setSymbol() |
| if((int) UNUM_FORMAT_SYMBOL_COUNT != (int) DecimalFormatSymbols::kFormatSymbolCount) { |
| errln("unum.h and decimfmt.h have inconsistent numbers of format symbols!"); |
| return; |
| } |
| |
| int i; |
| for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) { |
| foo.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i, UnicodeString((UChar32)(0x10330 + i))); |
| } |
| for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) { |
| if(foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) != UnicodeString((UChar32)(0x10330 + i))) { |
| errln("get/setSymbol did not roundtrip, got " + |
| foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) + |
| ", expected " + |
| UnicodeString((UChar32)(0x10330 + i))); |
| } |
| } |
| |
| DecimalFormatSymbols sym(Locale::getUS(), status); |
| |
| UnicodeString customDecSeperator("S"); |
| Verify(34.5, u"00.00", sym, u"34.50"); |
| sym.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, customDecSeperator); |
| Verify(34.5, u"00.00", sym, u"34S50"); |
| sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"P"); |
| Verify(34.5, u"00 %", sym, u"3450 P"); |
| sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, u"D"); |
| Verify(34.5, u"\u00a4##.##", sym, u"D\u00a034.50"); |
| sym.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u"|"); |
| Verify(3456.5, u"0,000.##", sym, u"3|456S5"); |
| |
| } |
| |
| void IntlTestDecimalFormatSymbols::testLastResortData() { |
| IcuTestErrorCode errorCode(*this, "testLastResortData"); |
| LocalPointer<DecimalFormatSymbols> lastResort( |
| DecimalFormatSymbols::createWithLastResortData(errorCode)); |
| if(errorCode.errIfFailureAndReset("DecimalFormatSymbols::createWithLastResortData() failed")) { |
| return; |
| } |
| DecimalFormatSymbols root(Locale::getRoot(), errorCode); |
| if(errorCode.errDataIfFailureAndReset("DecimalFormatSymbols(root) failed")) { |
| return; |
| } |
| // Note: It is not necessary that the last resort data matches the root locale, |
| // but it seems weird if most symbols did not match. |
| // Also, one purpose for calling operator==() is to find uninitialized memory in a debug build. |
| if(*lastResort == root) { |
| errln("DecimalFormatSymbols last resort data unexpectedly matches root"); |
| } |
| // Here we adjust for expected differences. |
| assertEquals("last-resort grouping separator", |
| "", lastResort->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)); |
| lastResort->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, ","); |
| assertEquals("last-resort monetary grouping separator", |
| "", lastResort->getSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)); |
| lastResort->setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, ","); |
| assertEquals("last-resort NaN", |
| UnicodeString((UChar)0xfffd), lastResort->getSymbol(DecimalFormatSymbols::kNaNSymbol)); |
| lastResort->setSymbol(DecimalFormatSymbols::kNaNSymbol, "NaN"); |
| // Check that now all of the symbols match root. |
| for(int32_t i = 0; i < DecimalFormatSymbols::kFormatSymbolCount; ++i) { |
| DecimalFormatSymbols::ENumberFormatSymbol e = (DecimalFormatSymbols::ENumberFormatSymbol)i; |
| assertEquals("last-resort symbol vs. root", root.getSymbol(e), lastResort->getSymbol(e)); |
| } |
| // Also, the CurrencySpacing patterns are empty in the last resort instance, |
| // but not in root. |
| Verify(1234567.25, "#,##0.##", *lastResort, "1,234,567.25"); |
| } |
| |
| void IntlTestDecimalFormatSymbols::testDigitSymbols() { |
| // This test does more in ICU4J than in ICU4C right now. |
| // In ICU4C, it is basically just a test for codePointZero and getConstDigitSymbol. |
| UChar defZero = u'0'; |
| UChar32 osmanyaZero = U'\U000104A0'; |
| static const UChar* osmanyaDigitStrings[] = { |
| u"\U000104A0", u"\U000104A1", u"\U000104A2", u"\U000104A3", u"\U000104A4", |
| u"\U000104A5", u"\U000104A6", u"\U000104A7", u"\U000104A8", u"\U000104A9" |
| }; |
| |
| IcuTestErrorCode status(*this, "testDigitSymbols()"); |
| DecimalFormatSymbols symbols(Locale("en"), status); |
| |
| if (defZero != symbols.getCodePointZero()) { |
| errln("ERROR: Code point zero be ASCII 0"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("i. ASCII Digit at index ") + Int64ToUnicodeString(i), |
| UnicodeString(u'0' + i), |
| symbols.getConstDigitSymbol(i)); |
| } |
| |
| for (int32_t i=0; i<=9; i++) { |
| DecimalFormatSymbols::ENumberFormatSymbol key = |
| i == 0 |
| ? DecimalFormatSymbols::kZeroDigitSymbol |
| : static_cast<DecimalFormatSymbols::ENumberFormatSymbol> |
| (DecimalFormatSymbols::kOneDigitSymbol + i - 1); |
| symbols.setSymbol(key, UnicodeString(osmanyaDigitStrings[i]), FALSE); |
| } |
| // NOTE: in ICU4J, the calculation of codePointZero is smarter; |
| // in ICU4C, it is more conservative and is only set if propogateDigits is true. |
| if (-1 != symbols.getCodePointZero()) { |
| errln("ERROR: Code point zero be invalid"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("ii. Osmanya digit at index ") + Int64ToUnicodeString(i), |
| UnicodeString(osmanyaDigitStrings[i]), |
| symbols.getConstDigitSymbol(i)); |
| } |
| |
| // Check Osmanya codePointZero |
| symbols.setSymbol( |
| DecimalFormatSymbols::kZeroDigitSymbol, |
| UnicodeString(osmanyaDigitStrings[0]), TRUE); |
| if (osmanyaZero != symbols.getCodePointZero()) { |
| errln("ERROR: Code point zero be Osmanya code point zero"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("iii. Osmanya digit at index ") + Int64ToUnicodeString(i), |
| UnicodeString(osmanyaDigitStrings[i]), |
| symbols.getConstDigitSymbol(i)); |
| } |
| |
| // Check after copy |
| DecimalFormatSymbols copy(symbols); |
| if (osmanyaZero != copy.getCodePointZero()) { |
| errln("ERROR: Code point zero be Osmanya code point zero"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("iv. After copy at index ") + Int64ToUnicodeString(i), |
| UnicodeString(osmanyaDigitStrings[i]), |
| copy.getConstDigitSymbol(i)); |
| } |
| |
| // Check when loaded from resource bundle |
| DecimalFormatSymbols fromData(Locale("en@numbers=osma"), status); |
| if (osmanyaZero != fromData.getCodePointZero()) { |
| errln("ERROR: Code point zero be Osmanya code point zero"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("v. Resource bundle at index ") + Int64ToUnicodeString(i), |
| UnicodeString(osmanyaDigitStrings[i]), |
| fromData.getConstDigitSymbol(i)); |
| } |
| |
| // Setting a digit somewhere in the middle should invalidate codePointZero |
| symbols.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, u"foo", FALSE); |
| if (-1 != symbols.getCodePointZero()) { |
| errln("ERROR: Code point zero be invalid"); |
| } |
| |
| // Reset digits to Latin |
| symbols.setSymbol( |
| DecimalFormatSymbols::kZeroDigitSymbol, |
| UnicodeString(defZero)); |
| if (defZero != symbols.getCodePointZero()) { |
| errln("ERROR: Code point zero be ASCII 0"); |
| } |
| for (int32_t i=0; i<=9; i++) { |
| assertEquals(UnicodeString("vi. ASCII Digit at index ") + Int64ToUnicodeString(i), |
| UnicodeString(u'0' + i), |
| symbols.getConstDigitSymbol(i)); |
| } |
| } |
| |
| void IntlTestDecimalFormatSymbols::testNumberingSystem() { |
| IcuTestErrorCode errorCode(*this, "testNumberingSystem"); |
| struct testcase { |
| const char* locid; |
| const char* nsname; |
| const char16_t* expected1; // Expected number format string |
| const char16_t* expected2; // Expected pattern separator |
| }; |
| static const testcase cases[] = { |
| {"en", "latn", u"1,234.56", u"%"}, |
| {"en", "arab", u"١٬٢٣٤٫٥٦", u"٪\u061C"}, |
| {"en", "mathsanb", u"𝟭,𝟮𝟯𝟰.𝟱𝟲", u"%"}, |
| {"en", "mymr", u"၁,၂၃၄.၅၆", u"%"}, |
| {"my", "latn", u"1,234.56", u"%"}, |
| {"my", "arab", u"١٬٢٣٤٫٥٦", u"٪\u061C"}, |
| {"my", "mathsanb", u"𝟭,𝟮𝟯𝟰.𝟱𝟲", u"%"}, |
| {"my", "mymr", u"၁,၂၃၄.၅၆", u"%"}, |
| {"ar", "latn", u"1,234.56", u"\u200E%\u200E"}, |
| {"ar", "arab", u"١٬٢٣٤٫٥٦", u"٪\u061C"}, |
| {"en@numbers=thai", "mymr", u"၁,၂၃၄.၅၆", u"%"}, // conflicting numbering system |
| }; |
| |
| for (int i=0; i<8; i++) { |
| testcase cas = cases[i]; |
| Locale loc(cas.locid); |
| LocalPointer<NumberingSystem> ns(NumberingSystem::createInstanceByName(cas.nsname, errorCode)); |
| if (errorCode.errDataIfFailureAndReset("NumberingSystem failed")) { |
| return; |
| } |
| UnicodeString expected1(cas.expected1); |
| UnicodeString expected2(cas.expected2); |
| DecimalFormatSymbols dfs(loc, *ns, errorCode); |
| if (errorCode.errDataIfFailureAndReset("DecimalFormatSymbols failed")) { |
| return; |
| } |
| Verify(1234.56, "#,##0.##", dfs, expected1); |
| // The percent sign differs by numbering system. |
| UnicodeString actual2 = dfs.getSymbol(DecimalFormatSymbols::kPercentSymbol); |
| assertEquals((UnicodeString) "Percent sign with " + cas.locid + " and " + cas.nsname, |
| expected2, |
| actual2); |
| } |
| } |
| |
| void IntlTestDecimalFormatSymbols::Verify(double value, const UnicodeString& pattern, |
| const DecimalFormatSymbols &sym, const UnicodeString& expected){ |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormat df(pattern, sym, status); |
| if(U_FAILURE(status)){ |
| errln("ERROR: construction of decimal format failed - %s", u_errorName(status)); |
| } |
| UnicodeString buffer; |
| FieldPosition pos(FieldPosition::DONT_CARE); |
| buffer = df.format(value, buffer, pos); |
| if(buffer != expected){ |
| errln((UnicodeString)"ERROR: format() returns wrong result\n Expected " + |
| expected + ", Got " + buffer); |
| } |
| } |
| |
| #endif /* #if !UCONFIG_NO_FORMATTING */ |