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) 2005-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ********************************************************************/ 8 #include "unicode/utypes.h" 9 10 #if !UCONFIG_NO_FORMATTING 11 #include "unicode/unum.h" 12 #include "unicode/ucurr.h" 13 #include "unicode/ustring.h" 14 #include "cintltst.h" 15 #include "cmemory.h" 16 #include "cstring.h" 17 18 static void expectInList(const char *isoCurrency, uint32_t currencyType, UBool isExpected) { 19 UErrorCode status = U_ZERO_ERROR; 20 const char *foundCurrency = NULL; 21 const char *currentCurrency; 22 UEnumeration *en = ucurr_openISOCurrencies(currencyType, &status); 23 if (U_FAILURE(status)) { 24 log_err("Error: ucurr_openISOCurrencies returned %s\n", myErrorName(status)); 25 return; 26 } 27 28 while ((currentCurrency = uenum_next(en, NULL, &status)) != NULL) { 29 if (strcmp(isoCurrency, currentCurrency) == 0) { 30 foundCurrency = currentCurrency; 31 break; 32 } 33 } 34 35 if ((foundCurrency != NULL) != isExpected) { 36 log_err("Error: could not find %s as expected. isExpected = %s type=0x%X\n", 37 isoCurrency, isExpected ? "TRUE" : "FALSE", currencyType); 38 } 39 uenum_close(en); 40 } 41 42 static void TestEnumList(void) { 43 expectInList("ADP", UCURR_ALL, TRUE); /* First in list */ 44 expectInList("ZWD", UCURR_ALL, TRUE); /* Last in list */ 45 46 expectInList("USD", UCURR_ALL, TRUE); 47 expectInList("USD", UCURR_COMMON, TRUE); 48 expectInList("USD", UCURR_UNCOMMON, FALSE); 49 expectInList("USD", UCURR_DEPRECATED, FALSE); 50 expectInList("USD", UCURR_NON_DEPRECATED, TRUE); 51 expectInList("USD", UCURR_COMMON|UCURR_DEPRECATED, FALSE); 52 expectInList("USD", UCURR_COMMON|UCURR_NON_DEPRECATED, TRUE); 53 expectInList("USD", UCURR_UNCOMMON|UCURR_DEPRECATED, FALSE); 54 expectInList("USD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED, FALSE); 55 56 expectInList("USN", UCURR_ALL, TRUE); 57 expectInList("USN", UCURR_COMMON, FALSE); 58 expectInList("USN", UCURR_UNCOMMON, TRUE); 59 expectInList("USN", UCURR_DEPRECATED, FALSE); 60 expectInList("USN", UCURR_NON_DEPRECATED, TRUE); 61 expectInList("USN", UCURR_COMMON|UCURR_DEPRECATED, FALSE); 62 expectInList("USN", UCURR_COMMON|UCURR_NON_DEPRECATED, FALSE); 63 expectInList("USN", UCURR_UNCOMMON|UCURR_DEPRECATED, FALSE); 64 expectInList("USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED, TRUE); 65 66 expectInList("DEM", UCURR_ALL, TRUE); 67 expectInList("DEM", UCURR_COMMON, TRUE); 68 expectInList("DEM", UCURR_UNCOMMON, FALSE); 69 expectInList("DEM", UCURR_DEPRECATED, TRUE); 70 expectInList("DEM", UCURR_NON_DEPRECATED, FALSE); 71 expectInList("DEM", UCURR_COMMON|UCURR_DEPRECATED, TRUE); 72 expectInList("DEM", UCURR_COMMON|UCURR_NON_DEPRECATED, FALSE); 73 expectInList("DEM", UCURR_UNCOMMON|UCURR_DEPRECATED, FALSE); 74 expectInList("DEM", UCURR_UNCOMMON|UCURR_NON_DEPRECATED, FALSE); 75 76 expectInList("XEU", UCURR_ALL, TRUE); 77 expectInList("XEU", UCURR_COMMON, FALSE); 78 expectInList("XEU", UCURR_UNCOMMON, TRUE); 79 expectInList("XEU", UCURR_DEPRECATED, TRUE); 80 expectInList("XEU", UCURR_NON_DEPRECATED, FALSE); 81 expectInList("XEU", UCURR_COMMON|UCURR_DEPRECATED, FALSE); 82 expectInList("XEU", UCURR_COMMON|UCURR_NON_DEPRECATED, FALSE); 83 expectInList("XEU", UCURR_UNCOMMON|UCURR_DEPRECATED, TRUE); 84 expectInList("XEU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED, FALSE); 85 86 } 87 88 static void TestEnumListReset(void) { 89 UErrorCode status = U_ZERO_ERROR; 90 const char *currency1; 91 const char *currency2; 92 UEnumeration *en = ucurr_openISOCurrencies(UCURR_ALL, &status); 93 if (U_FAILURE(status)) { 94 log_err("Error: ucurr_openISOCurrencies returned %s\n", myErrorName(status)); 95 return; 96 } 97 98 currency1 = uenum_next(en, NULL, &status); 99 uenum_reset(en, &status); 100 currency2 = uenum_next(en, NULL, &status); 101 if (U_FAILURE(status)) { 102 log_err("Error: uenum_next or uenum_reset returned %s\n", myErrorName(status)); 103 return; 104 } 105 /* The first item's pointer in the list should be the same between resets. */ 106 if (currency1 != currency2) { 107 log_err("Error: reset doesn't work %s != %s\n", currency1, currency2); 108 } 109 uenum_close(en); 110 } 111 112 static int32_t checkItemCount(uint32_t currencyType) { 113 UErrorCode status = U_ZERO_ERROR; 114 int32_t originalCount, count; 115 UEnumeration *en = ucurr_openISOCurrencies(currencyType, &status); 116 int32_t expectedLen = 3, len; 117 if (U_FAILURE(status)) { 118 log_err("Error: ucurr_openISOCurrencies returned %s\n", myErrorName(status)); 119 return -1; 120 } 121 122 originalCount = uenum_count(en, &status); 123 for (count=0;;count++) { 124 const char *str = uenum_next(en, &len, &status); 125 if (str == NULL || len != expectedLen || strlen(str) != expectedLen) { 126 break; 127 } 128 } 129 130 if (originalCount != count) { 131 log_err("Error: uenum_count returned the wrong value (type = 0x%X). Got: %d Expected %d\n", 132 currencyType, count, originalCount); 133 } 134 if (U_FAILURE(status)) { 135 log_err("Error: uenum_next got an error: %s\n", u_errorName(status)); 136 } 137 uenum_close(en); 138 return count; 139 } 140 141 static void TestEnumListCount(void) { 142 checkItemCount(UCURR_ALL); 143 checkItemCount(UCURR_COMMON); 144 checkItemCount(UCURR_UNCOMMON); 145 checkItemCount(UCURR_DEPRECATED); 146 checkItemCount(UCURR_NON_DEPRECATED); 147 checkItemCount(UCURR_COMMON|UCURR_DEPRECATED); 148 checkItemCount(UCURR_COMMON|UCURR_NON_DEPRECATED); 149 checkItemCount(UCURR_UNCOMMON|UCURR_DEPRECATED); 150 checkItemCount(UCURR_UNCOMMON|UCURR_NON_DEPRECATED); 151 152 if (checkItemCount(UCURR_DEPRECATED|UCURR_NON_DEPRECATED) != 0) { 153 log_err("Error: UCURR_DEPRECATED|UCURR_NON_DEPRECATED should return 0 items\n"); 154 } 155 if (checkItemCount(UCURR_COMMON|UCURR_UNCOMMON) != 0) { 156 log_err("Error: UCURR_DEPRECATED|UCURR_NON_DEPRECATED should return 0 items\n"); 157 } 158 } 159 160 static void TestFractionDigitOverride(void) { 161 UErrorCode status = U_ZERO_ERROR; 162 UNumberFormat *fmt = unum_open(UNUM_CURRENCY, NULL, 0, "hu_HU", NULL, &status); 163 UChar buffer[256]; 164 UChar expectedBuf[256]; 165 const char expectedFirst[] = "123,46\\u00A0Ft"; /* changed to use 2 fraction digits */ 166 const char expectedSecond[] = "123,46\\u00A0Ft"; 167 const char expectedThird[] = "123,456\\u00A0Ft"; 168 if (U_FAILURE(status)) { 169 log_data_err("Error: unum_open returned %s (Are you missing data?)\n", myErrorName(status)); 170 return; 171 } 172 /* Make sure that you can format normal fraction digits. */ 173 unum_formatDouble(fmt, 123.456, buffer, UPRV_LENGTHOF(buffer), NULL, &status); 174 u_unescape(expectedFirst, expectedBuf, strlen(expectedFirst)+1); 175 if (u_strcmp(buffer, expectedBuf) != 0) { 176 log_err("Error: unum_formatDouble didn't return %s\n", expectedFirst); 177 } 178 /* Make sure that you can format 2 fraction digits. */ 179 unum_setAttribute(fmt, UNUM_FRACTION_DIGITS, 2); 180 unum_formatDouble(fmt, 123.456, buffer, UPRV_LENGTHOF(buffer), NULL, &status); 181 u_unescape(expectedSecond, expectedBuf, strlen(expectedSecond)+1); 182 if (u_strcmp(buffer, expectedBuf) != 0) { 183 log_err("Error: unum_formatDouble didn't return %s\n", expectedSecond); 184 } 185 /* Make sure that you can format more fraction digits. */ 186 unum_setAttribute(fmt, UNUM_FRACTION_DIGITS, 3); 187 unum_formatDouble(fmt, 123.456, buffer, UPRV_LENGTHOF(buffer), NULL, &status); 188 u_unescape(expectedThird, expectedBuf, strlen(expectedThird)+1); 189 if (u_strcmp(buffer, expectedBuf) != 0) { 190 log_err("Error: unum_formatDouble didn't return %s\n", expectedThird); 191 } 192 unum_close(fmt); 193 } 194 195 static void TestPrefixSuffix(void) { 196 int32_t pos; 197 UErrorCode status; 198 double result1 = 0.0, result2 = 0.0; 199 UNumberFormat* parser; 200 UChar buffer[4]; 201 static const UChar TEST_NUMBER[] = {0x0024,0x0031,0x0032,0x002E,0x0030,0x0030,0}; /* $12.00 */ 202 static const UChar NEG_PREFIX[] = {0x005B,0}; /* "[" */ 203 static const UChar NEG_SUFFIX[] = {0x005D,0}; /* "]" */ 204 205 206 status = U_ZERO_ERROR; 207 parser = unum_open(UNUM_CURRENCY, NULL, -1, "en_US", NULL, &status); 208 if (U_FAILURE(status)) { 209 log_data_err("Error: unum_open returned %s (Are you missing data?)\n", u_errorName(status)); 210 return; 211 } 212 213 pos = 0; 214 status = U_ZERO_ERROR; 215 result1 = unum_parseDoubleCurrency(parser, TEST_NUMBER, -1, &pos, buffer, &status); 216 217 unum_setTextAttribute(parser, UNUM_NEGATIVE_SUFFIX, NEG_SUFFIX, -1, &status); 218 unum_setTextAttribute(parser, UNUM_NEGATIVE_PREFIX, NEG_PREFIX, -1, &status); 219 if (U_FAILURE(status)) { 220 log_err("Error: unum_setTextAttribute returned %s\n", u_errorName(status)); 221 return; 222 } 223 224 pos = 0; 225 result2 = unum_parseDoubleCurrency(parser, TEST_NUMBER, -1, &pos, buffer, &status); 226 if (result1 != result2 || U_FAILURE(status)) { 227 log_err("Error: unum_parseDoubleCurrency didn't return the same value for same string %f %f %s\n", 228 result1, result2, u_errorName(status)); 229 } 230 unum_close(parser); 231 } 232 233 typedef struct { 234 const char* alphaCode; 235 int32_t numericCode; 236 } NumCodeTestEntry; 237 238 static const NumCodeTestEntry NUMCODE_TESTDATA[] = { 239 {"USD", 840}, 240 {"Usd", 840}, /* mixed casing */ 241 {"EUR", 978}, 242 {"JPY", 392}, 243 {"XFU", 0}, /* XFU: no numeric code */ 244 {"ZZZ", 0}, /* ZZZ: undefined ISO currency code */ 245 {"bogus", 0}, /* bogus code */ 246 {0, 0}, 247 }; 248 249 static void TestNumericCode(void) { 250 UChar code[8]; // at least one longer than the longest alphaCode 251 int32_t i; 252 int32_t numCode; 253 254 for (i = 0; NUMCODE_TESTDATA[i].alphaCode; i++) { 255 int32_t length = uprv_strlen(NUMCODE_TESTDATA[i].alphaCode); 256 u_charsToUChars(NUMCODE_TESTDATA[i].alphaCode, code, length + 1); // +1 includes the NUL 257 numCode = ucurr_getNumericCode(code); 258 if (numCode != NUMCODE_TESTDATA[i].numericCode) { 259 log_data_err("Error: ucurr_getNumericCode returned %d for currency %s, expected - %d\n", 260 numCode, NUMCODE_TESTDATA[i].alphaCode, NUMCODE_TESTDATA[i].numericCode); 261 } 262 } 263 } 264 265 void addCurrencyTest(TestNode** root); 266 267 #define TESTCASE(x) addTest(root, &x, "tsformat/currtest/" #x) 268 269 void addCurrencyTest(TestNode** root) 270 { 271 TESTCASE(TestEnumList); 272 TESTCASE(TestEnumListReset); 273 TESTCASE(TestEnumListCount); 274 TESTCASE(TestFractionDigitOverride); 275 TESTCASE(TestPrefixSuffix); 276 TESTCASE(TestNumericCode); 277 } 278 279 #endif /* #if !UCONFIG_NO_FORMATTING */ 280