1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * Copyright (c) 2011-2014, International Business Machines Corporation 5 * and others. All Rights Reserved. 6 ********************************************************************/ 7 /* C API TEST FOR PLURAL RULES */ 8 9 #include "unicode/utypes.h" 10 11 #if !UCONFIG_NO_FORMATTING 12 13 #include "unicode/upluralrules.h" 14 #include "unicode/ustring.h" 15 #include "unicode/uenum.h" 16 #include "cintltst.h" 17 #include "cmemory.h" 18 #include "cstring.h" 19 20 static void TestPluralRules(void); 21 static void TestOrdinalRules(void); 22 static void TestGetKeywords(void); 23 24 void addPluralRulesTest(TestNode** root); 25 26 #define TESTCASE(x) addTest(root, &x, "tsformat/cpluralrulestest/" #x) 27 28 void addPluralRulesTest(TestNode** root) 29 { 30 TESTCASE(TestPluralRules); 31 TESTCASE(TestOrdinalRules); 32 TESTCASE(TestGetKeywords); 33 } 34 35 typedef struct { 36 const char * locale; 37 double number; 38 const char * keywordExpected; 39 const char * keywordExpectedForDecimals; 40 } PluralRulesTestItem; 41 42 /* Just a small set of tests for now, other functionality is tested in the C++ tests */ 43 static const PluralRulesTestItem testItems[] = { 44 { "en", 0, "other", "other" }, 45 { "en", 0.5, "other", "other" }, 46 { "en", 1, "one", "other" }, 47 { "en", 1.5, "other", "other" }, 48 { "en", 2, "other", "other" }, 49 { "fr", 0, "one", "one" }, 50 { "fr", 0.5, "one", "one" }, 51 { "fr", 1, "one", "one" }, 52 { "fr", 1.5, "one", "one" }, 53 { "fr", 2, "other", "other" }, 54 { "ru", 0, "many", "other" }, 55 { "ru", 0.5, "other", "other" }, 56 { "ru", 1, "one", "other" }, 57 { "ru", 1.5, "other", "other" }, 58 { "ru", 2, "few", "other" }, 59 { "ru", 5, "many", "other" }, 60 { "ru", 10, "many", "other" }, 61 { "ru", 11, "many", "other" }, 62 { NULL, 0, NULL, NULL } 63 }; 64 65 static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */ 66 67 enum { 68 kKeywordBufLen = 32 69 }; 70 71 static void TestPluralRules() 72 { 73 const PluralRulesTestItem * testItemPtr; 74 log_verbose("\nTesting uplrules_open() and uplrules_select() with various parameters\n"); 75 for ( testItemPtr = testItems; testItemPtr->locale != NULL; ++testItemPtr ) { 76 UErrorCode status = U_ZERO_ERROR; 77 UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status); 78 if ( U_SUCCESS(status) ) { 79 UNumberFormat* unumfmt; 80 UChar keyword[kKeywordBufLen]; 81 UChar keywordExpected[kKeywordBufLen]; 82 int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status); 83 if (keywdLen >= kKeywordBufLen) { 84 keyword[kKeywordBufLen-1] = 0; 85 } 86 if ( U_SUCCESS(status) ) { 87 u_unescape(testItemPtr->keywordExpected, keywordExpected, kKeywordBufLen); 88 if ( u_strcmp(keyword, keywordExpected) != 0 ) { 89 char bcharBuf[kKeywordBufLen]; 90 log_data_err("ERROR: uplrules_select for locale %s, number %.1f: expect %s, get %s\n", 91 testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpected, u_austrcpy(bcharBuf,keyword) ); 92 } 93 } else { 94 log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n", 95 testItemPtr->locale, testItemPtr->number, myErrorName(status) ); 96 } 97 98 status = U_ZERO_ERROR; 99 unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status); 100 if ( U_SUCCESS(status) ) { 101 keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status); 102 if (keywdLen >= kKeywordBufLen) { 103 keyword[kKeywordBufLen-1] = 0; 104 } 105 if ( U_SUCCESS(status) ) { 106 u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen); 107 if ( u_strcmp(keyword, keywordExpected) != 0 ) { 108 char bcharBuf[kKeywordBufLen]; 109 log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n", 110 testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) ); 111 } 112 } else { 113 log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n", 114 testItemPtr->locale, testItemPtr->number, myErrorName(status) ); 115 } 116 unum_close(unumfmt); 117 } else { 118 log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) ); 119 } 120 121 uplrules_close(uplrules); 122 } else { 123 log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) ); 124 } 125 } 126 } 127 128 static void TestOrdinalRules() { 129 U_STRING_DECL(two, "two", 3); 130 UChar keyword[8]; 131 int32_t length; 132 UErrorCode errorCode = U_ZERO_ERROR; 133 UPluralRules* upr = uplrules_openForType("en", UPLURAL_TYPE_ORDINAL, &errorCode); 134 if (U_FAILURE(errorCode)) { 135 log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode)); 136 return; 137 } 138 U_STRING_INIT(two, "two", 3); 139 length = uplrules_select(upr, 2., keyword, 8, &errorCode); 140 if (U_FAILURE(errorCode) || u_strCompare(keyword, length, two, 3, FALSE) != 0) { 141 log_data_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode)); 142 } 143 uplrules_close(upr); 144 } 145 146 /* items for TestGetKeywords */ 147 148 /* all possible plural keywords, in alphabetical order */ 149 static const char* knownKeywords[] = { 150 "few", 151 "many", 152 "one", 153 "other", 154 "two", 155 "zero" 156 }; 157 enum { 158 kNumKeywords = UPRV_LENGTHOF(knownKeywords) 159 }; 160 161 /* Return the index of keyword in knownKeywords[], or -1 if not found */ 162 static int32_t getKeywordIndex(const char* keyword) { 163 int32_t i, compare; 164 for (i = 0; i < kNumKeywords && (compare = uprv_strcmp(keyword,knownKeywords[i])) >= 0; i++) { 165 if (compare == 0) { 166 return i; 167 } 168 } 169 return -1; 170 } 171 172 typedef struct { 173 const char* locale; 174 const char* keywords[kNumKeywords + 1]; 175 } KeywordsForLang; 176 177 static const KeywordsForLang getKeywordsItems[] = { 178 { "zh", { "other" } }, 179 { "en", { "one", "other" } }, 180 { "fr", { "one", "other" } }, 181 { "lv", { "zero", "one", "other" } }, 182 { "hr", { "one", "few", "other" } }, 183 { "sl", { "one", "two", "few", "other" } }, 184 { "he", { "one", "two", "many", "other" } }, 185 { "cs", { "one", "few", "many", "other" } }, 186 { "ar", { "zero", "one", "two", "few", "many" , "other" } }, 187 { NULL, { NULL } } 188 }; 189 190 static void TestGetKeywords() { 191 /* 192 * We don't know the order in which the enumeration will return keywords, 193 * so we have an array with known keywords in a fixed order and then 194 * parallel arrays of flags for expected and actual results that indicate 195 * which keywords are expected to be or actually are found. 196 */ 197 const KeywordsForLang* itemPtr = getKeywordsItems; 198 for (; itemPtr->locale != NULL; itemPtr++) { 199 UPluralRules* uplrules; 200 UEnumeration* uenum; 201 UBool expectKeywords[kNumKeywords]; 202 UBool getKeywords[kNumKeywords]; 203 int32_t i, iKnown; 204 UErrorCode status = U_ZERO_ERROR; 205 206 /* initialize arrays for expected and get results */ 207 for (i = 0; i < kNumKeywords; i++) { 208 expectKeywords[i] = FALSE; 209 getKeywords[i] = FALSE; 210 } 211 for (i = 0; i < kNumKeywords && itemPtr->keywords[i] != NULL; i++) { 212 iKnown = getKeywordIndex(itemPtr->keywords[i]); 213 if (iKnown >= 0) { 214 expectKeywords[iKnown] = TRUE; 215 } 216 } 217 218 uplrules = uplrules_openForType(itemPtr->locale, UPLURAL_TYPE_CARDINAL, &status); 219 if (U_FAILURE(status)) { 220 log_err("FAIL: uplrules_openForType for locale %s, UPLURAL_TYPE_CARDINAL: %s\n", itemPtr->locale, myErrorName(status) ); 221 continue; 222 } 223 uenum = uplrules_getKeywords(uplrules, &status); 224 if (U_FAILURE(status)) { 225 log_err("FAIL: uplrules_getKeywords for locale %s: %s\n", itemPtr->locale, myErrorName(status) ); 226 } else { 227 const char* keyword; 228 int32_t keywordLen, keywordCount = 0; 229 while ((keyword = uenum_next(uenum, &keywordLen, &status)) != NULL && U_SUCCESS(status)) { 230 iKnown = getKeywordIndex(keyword); 231 if (iKnown < 0) { 232 log_err("FAIL: uplrules_getKeywords for locale %s, unknown keyword %s\n", itemPtr->locale, keyword ); 233 } else { 234 getKeywords[iKnown] = TRUE; 235 } 236 keywordCount++; 237 } 238 if (keywordCount > kNumKeywords) { 239 log_err("FAIL: uplrules_getKeywords for locale %s, got too many keywords %d\n", itemPtr->locale, keywordCount ); 240 } 241 if (uprv_memcmp(expectKeywords, getKeywords, kNumKeywords) != 0) { 242 log_err("FAIL: uplrules_getKeywords for locale %s, got wrong keyword set; with reference to knownKeywords:\n" 243 " expected { %d %d %d %d %d %d },\n" 244 " got { %d %d %d %d %d %d }\n", itemPtr->locale, 245 expectKeywords[0], expectKeywords[1], expectKeywords[2], expectKeywords[3], expectKeywords[4], expectKeywords[5], 246 getKeywords[0], getKeywords[1], getKeywords[2], getKeywords[3], getKeywords[4], getKeywords[5] ); 247 } 248 uenum_close(uenum); 249 } 250 251 uplrules_close(uplrules); 252 } 253 } 254 255 #endif /* #if !UCONFIG_NO_FORMATTING */ 256