1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * COPYRIGHT: 5 * Copyright (c) 1997-2013, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ********************************************************************/ 8 9 #include "unicode/utypes.h" 10 11 #if !UCONFIG_NO_FORMATTING 12 13 #include "unicode/dcfmtsym.h" 14 #include "unicode/decimfmt.h" 15 #include "unicode/unum.h" 16 #include "tsdcfmsy.h" 17 18 void IntlTestDecimalFormatSymbols::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 19 { 20 if (exec) { 21 logln("TestSuite DecimalFormatSymbols:"); 22 } 23 TESTCASE_AUTO_BEGIN; 24 TESTCASE_AUTO(testSymbols); 25 TESTCASE_AUTO(testLastResortData); 26 TESTCASE_AUTO(testNumberingSystem); 27 TESTCASE_AUTO_END; 28 } 29 30 /** 31 * Test the API of DecimalFormatSymbols; primarily a simple get/set set. 32 */ 33 void IntlTestDecimalFormatSymbols::testSymbols(/* char *par */) 34 { 35 UErrorCode status = U_ZERO_ERROR; 36 37 DecimalFormatSymbols fr(Locale::getFrench(), status); 38 if(U_FAILURE(status)) { 39 errcheckln(status, "ERROR: Couldn't create French DecimalFormatSymbols - %s", u_errorName(status)); 40 return; 41 } 42 43 status = U_ZERO_ERROR; 44 DecimalFormatSymbols en(Locale::getEnglish(), status); 45 if(U_FAILURE(status)) { 46 errcheckln(status, "ERROR: Couldn't create English DecimalFormatSymbols - %s", u_errorName(status)); 47 return; 48 } 49 50 if(en == fr || ! (en != fr) ) { 51 errln("ERROR: English DecimalFormatSymbols equal to French"); 52 } 53 54 // just do some VERY basic tests to make sure that get/set work 55 56 UnicodeString zero = en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol); 57 fr.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero); 58 if(fr.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) { 59 errln("ERROR: get/set ZeroDigit failed"); 60 } 61 62 UnicodeString group = en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); 63 fr.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, group); 64 if(fr.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) { 65 errln("ERROR: get/set GroupingSeparator failed"); 66 } 67 68 UnicodeString decimal = en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 69 fr.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, decimal); 70 if(fr.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) { 71 errln("ERROR: get/set DecimalSeparator failed"); 72 } 73 74 UnicodeString perMill = en.getSymbol(DecimalFormatSymbols::kPerMillSymbol); 75 fr.setSymbol(DecimalFormatSymbols::kPerMillSymbol, perMill); 76 if(fr.getSymbol(DecimalFormatSymbols::kPerMillSymbol) != en.getSymbol(DecimalFormatSymbols::kPerMillSymbol)) { 77 errln("ERROR: get/set PerMill failed"); 78 } 79 80 UnicodeString percent = en.getSymbol(DecimalFormatSymbols::kPercentSymbol); 81 fr.setSymbol(DecimalFormatSymbols::kPercentSymbol, percent); 82 if(fr.getSymbol(DecimalFormatSymbols::kPercentSymbol) != en.getSymbol(DecimalFormatSymbols::kPercentSymbol)) { 83 errln("ERROR: get/set Percent failed"); 84 } 85 86 UnicodeString digit(en.getSymbol(DecimalFormatSymbols::kDigitSymbol)); 87 fr.setSymbol(DecimalFormatSymbols::kDigitSymbol, digit); 88 if(fr.getSymbol(DecimalFormatSymbols::kDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kDigitSymbol)) { 89 errln("ERROR: get/set Percent failed"); 90 } 91 92 UnicodeString patternSeparator = en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 93 fr.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, patternSeparator); 94 if(fr.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) { 95 errln("ERROR: get/set PatternSeparator failed"); 96 } 97 98 UnicodeString infinity(en.getSymbol(DecimalFormatSymbols::kInfinitySymbol)); 99 fr.setSymbol(DecimalFormatSymbols::kInfinitySymbol, infinity); 100 UnicodeString infinity2(fr.getSymbol(DecimalFormatSymbols::kInfinitySymbol)); 101 if(infinity != infinity2) { 102 errln("ERROR: get/set Infinity failed"); 103 } 104 105 UnicodeString nan(en.getSymbol(DecimalFormatSymbols::kNaNSymbol)); 106 fr.setSymbol(DecimalFormatSymbols::kNaNSymbol, nan); 107 UnicodeString nan2(fr.getSymbol(DecimalFormatSymbols::kNaNSymbol)); 108 if(nan != nan2) { 109 errln("ERROR: get/set NaN failed"); 110 } 111 112 UnicodeString minusSign = en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol); 113 fr.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, minusSign); 114 if(fr.getSymbol(DecimalFormatSymbols::kMinusSignSymbol) != en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol)) { 115 errln("ERROR: get/set MinusSign failed"); 116 } 117 118 UnicodeString exponential(en.getSymbol(DecimalFormatSymbols::kExponentialSymbol)); 119 fr.setSymbol(DecimalFormatSymbols::kExponentialSymbol, exponential); 120 if(fr.getSymbol(DecimalFormatSymbols::kExponentialSymbol) != en.getSymbol(DecimalFormatSymbols::kExponentialSymbol)) { 121 errln("ERROR: get/set Exponential failed"); 122 } 123 124 // Test get currency spacing before the currency. 125 status = U_ZERO_ERROR; 126 for (int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; i++) { 127 UnicodeString enCurrencyPattern = en.getPatternForCurrencySpacing( 128 (UCurrencySpacing)i, TRUE, status); 129 if(U_FAILURE(status)) { 130 errln("Error: cannot get CurrencyMatch for locale:en"); 131 status = U_ZERO_ERROR; 132 } 133 UnicodeString frCurrencyPattern = fr.getPatternForCurrencySpacing( 134 (UCurrencySpacing)i, TRUE, status); 135 if(U_FAILURE(status)) { 136 errln("Error: cannot get CurrencyMatch for locale:fr"); 137 } 138 if (enCurrencyPattern != frCurrencyPattern) { 139 errln("ERROR: get CurrencySpacing failed"); 140 } 141 } 142 // Test get currencySpacing after the currency. 143 status = U_ZERO_ERROR; 144 for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) { 145 UnicodeString enCurrencyPattern = en.getPatternForCurrencySpacing( 146 (UCurrencySpacing)i, FALSE, status); 147 if(U_FAILURE(status)) { 148 errln("Error: cannot get CurrencyMatch for locale:en"); 149 status = U_ZERO_ERROR; 150 } 151 UnicodeString frCurrencyPattern = fr.getPatternForCurrencySpacing( 152 (UCurrencySpacing)i, FALSE, status); 153 if(U_FAILURE(status)) { 154 errln("Error: cannot get CurrencyMatch for locale:fr"); 155 } 156 if (enCurrencyPattern != frCurrencyPattern) { 157 errln("ERROR: get CurrencySpacing failed"); 158 } 159 } 160 // Test set curerncySpacing APIs 161 status = U_ZERO_ERROR; 162 UnicodeString dash = UnicodeString("-"); 163 en.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, dash); 164 UnicodeString enCurrencyInsert = en.getPatternForCurrencySpacing( 165 UNUM_CURRENCY_INSERT, TRUE, status); 166 if (dash != enCurrencyInsert) { 167 errln("Error: Failed to setCurrencyInsert for locale:en"); 168 } 169 170 status = U_ZERO_ERROR; 171 DecimalFormatSymbols foo(status); 172 173 DecimalFormatSymbols bar(foo); 174 175 en = fr; 176 177 if(en != fr || foo != bar) { 178 errln("ERROR: Copy Constructor or Assignment failed"); 179 } 180 181 // test get/setSymbol() 182 if((int) UNUM_FORMAT_SYMBOL_COUNT != (int) DecimalFormatSymbols::kFormatSymbolCount) { 183 errln("unum.h and decimfmt.h have inconsistent numbers of format symbols!"); 184 return; 185 } 186 187 int i; 188 for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) { 189 foo.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i, UnicodeString((UChar32)(0x10330 + i))); 190 } 191 for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) { 192 if(foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) != UnicodeString((UChar32)(0x10330 + i))) { 193 errln("get/setSymbol did not roundtrip, got " + 194 foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) + 195 ", expected " + 196 UnicodeString((UChar32)(0x10330 + i))); 197 } 198 } 199 200 DecimalFormatSymbols sym(Locale::getUS(), status); 201 202 UnicodeString customDecSeperator("S"); 203 Verify(34.5, (UnicodeString)"00.00", sym, (UnicodeString)"34.50"); 204 sym.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, customDecSeperator); 205 Verify(34.5, (UnicodeString)"00.00", sym, (UnicodeString)"34S50"); 206 sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UnicodeString)"P"); 207 Verify(34.5, (UnicodeString)"00 %", sym, (UnicodeString)"3450 P"); 208 sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, (UnicodeString)"D"); 209 Verify(34.5, CharsToUnicodeString("\\u00a4##.##"), sym, (UnicodeString)"D34.5"); 210 sym.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, (UnicodeString)"|"); 211 Verify(3456.5, (UnicodeString)"0,000.##", sym, (UnicodeString)"3|456S5"); 212 213 } 214 215 void IntlTestDecimalFormatSymbols::testLastResortData() { 216 IcuTestErrorCode errorCode(*this, "testLastResortData"); 217 LocalPointer<DecimalFormatSymbols> lastResort( 218 DecimalFormatSymbols::createWithLastResortData(errorCode)); 219 if(errorCode.logIfFailureAndReset("DecimalFormatSymbols::createWithLastResortData() failed")) { 220 return; 221 } 222 DecimalFormatSymbols root(Locale::getRoot(), errorCode); 223 if(errorCode.logDataIfFailureAndReset("DecimalFormatSymbols(root) failed")) { 224 return; 225 } 226 // Note: It is not necessary that the last resort data matches the root locale, 227 // but it seems weird if most symbols did not match. 228 // Also, one purpose for calling operator==() is to find uninitialized memory in a debug build. 229 if(*lastResort == root) { 230 errln("DecimalFormatSymbols last resort data unexpectedly matches root"); 231 } 232 // Here we adjust for expected differences. 233 assertEquals("last-resort grouping separator", 234 "", lastResort->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)); 235 lastResort->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, ","); 236 assertEquals("last-resort monetary grouping separator", 237 "", lastResort->getSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)); 238 lastResort->setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, ","); 239 assertEquals("last-resort NaN", 240 UnicodeString((UChar)0xfffd), lastResort->getSymbol(DecimalFormatSymbols::kNaNSymbol)); 241 lastResort->setSymbol(DecimalFormatSymbols::kNaNSymbol, "NaN"); 242 // Check that now all of the symbols match root. 243 for(int32_t i = 0; i < DecimalFormatSymbols::kFormatSymbolCount; ++i) { 244 DecimalFormatSymbols::ENumberFormatSymbol e = (DecimalFormatSymbols::ENumberFormatSymbol)i; 245 assertEquals("last-resort symbol vs. root", root.getSymbol(e), lastResort->getSymbol(e)); 246 } 247 // Also, the CurrencySpacing patterns are empty in the last resort instance, 248 // but not in root. 249 Verify(1234567.25, "#,##0.##", *lastResort, "1,234,567.25"); 250 } 251 252 void IntlTestDecimalFormatSymbols::testNumberingSystem() { 253 IcuTestErrorCode errorCode(*this, "testNumberingSystem"); 254 struct testcase { 255 const char* locid; 256 const char* nsname; 257 const char16_t* expected1; // Expected number format string 258 const char16_t* expected2; // Expected pattern separator 259 }; 260 static const testcase cases[9] = { 261 {"en", "latn", u"1,234.56", u";"}, 262 {"en", "arab", u"", u""}, 263 {"en", "mathsanb", u",.", u";"}, 264 {"en", "mymr", u",.", u";"}, 265 {"my", "latn", u"1,234.56", u";"}, 266 {"my", "arab", u"", u""}, 267 {"my", "mathsanb", u",.", u";"}, 268 {"my", "mymr", u",.", u""}, 269 {"en@numbers=thai", "mymr", u",.", u";"}, // conflicting numbering system 270 }; 271 272 for (int i=0; i<8; i++) { 273 testcase cas = cases[i]; 274 Locale loc(cas.locid); 275 LocalPointer<NumberingSystem> ns(NumberingSystem::createInstanceByName(cas.nsname, errorCode)); 276 if (errorCode.logDataIfFailureAndReset("NumberingSystem failed")) { 277 return; 278 } 279 UnicodeString expected1(cas.expected1); 280 UnicodeString expected2(cas.expected2); 281 DecimalFormatSymbols dfs(loc, *ns, errorCode); 282 if (errorCode.logDataIfFailureAndReset("DecimalFormatSymbols failed")) { 283 return; 284 } 285 Verify(1234.56, "#,##0.##", dfs, expected1); 286 // The pattern separator is something that differs by numbering system in my@numbers=mymr. 287 UnicodeString actual2 = dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 288 if (expected2 != actual2) { 289 errln((UnicodeString)"ERROR: DecimalFormatSymbols returned pattern separator " + actual2 290 + " but we expected " + expected2); 291 } 292 } 293 } 294 295 void IntlTestDecimalFormatSymbols::Verify(double value, const UnicodeString& pattern, 296 const DecimalFormatSymbols &sym, const UnicodeString& expected){ 297 UErrorCode status = U_ZERO_ERROR; 298 DecimalFormat df(pattern, sym, status); 299 if(U_FAILURE(status)){ 300 errln("ERROR: construction of decimal format failed - %s", u_errorName(status)); 301 } 302 UnicodeString buffer; 303 FieldPosition pos(FieldPosition::DONT_CARE); 304 buffer = df.format(value, buffer, pos); 305 if(buffer != expected){ 306 errln((UnicodeString)"ERROR: format() returns wrong result\n Expected " + 307 expected + ", Got " + buffer); 308 } 309 } 310 311 #endif /* #if !UCONFIG_NO_FORMATTING */ 312