• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "unicode/unumberformatter.h"
17 #include "cintltst.h"
18 #include "cmemory.h"
19 #include "cstring.h"
20 
21 static void TestPluralRules(void);
22 static void TestOrdinalRules(void);
23 static void TestGetKeywords(void);
24 static void TestFormatted(void);
25 
26 void addPluralRulesTest(TestNode** root);
27 
28 #define TESTCASE(x) addTest(root, &x, "tsformat/cpluralrulestest/" #x)
29 
addPluralRulesTest(TestNode ** root)30 void addPluralRulesTest(TestNode** root)
31 {
32     TESTCASE(TestPluralRules);
33     TESTCASE(TestOrdinalRules);
34     TESTCASE(TestGetKeywords);
35     TESTCASE(TestFormatted);
36 }
37 
38 typedef struct {
39     const char * locale;
40     double       number;
41     const char * keywordExpected;
42     const char * keywordExpectedForDecimals;
43 } PluralRulesTestItem;
44 
45 /* Just a small set of tests for now, other functionality is tested in the C++ tests */
46 static const PluralRulesTestItem testItems[] = {
47     { "en",   0, "other", "other" },
48     { "en", 0.5, "other", "other" },
49     { "en",   1, "one",   "other" },
50     { "en", 1.5, "other", "other" },
51     { "en",   2, "other", "other" },
52     { "fr",   0, "one",   "one" },
53     { "fr", 0.5, "one",   "one" },
54     { "fr",   1, "one",   "one" },
55     { "fr", 1.5, "one",   "one" },
56     { "fr",   2, "other", "other" },
57     { "ru",   0, "many",  "other" },
58     { "ru", 0.5, "other", "other" },
59     { "ru",   1, "one",   "other" },
60     { "ru", 1.5, "other", "other" },
61     { "ru",   2, "few",   "other" },
62     { "ru",   5, "many",  "other" },
63     { "ru",  10, "many",  "other" },
64     { "ru",  11, "many",  "other" },
65     { NULL,   0, NULL,    NULL }
66 };
67 
68 static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
69 
70 enum {
71     kKeywordBufLen = 32
72 };
73 
TestPluralRules()74 static void TestPluralRules()
75 {
76     const PluralRulesTestItem * testItemPtr;
77     log_verbose("\nTesting uplrules_open() and uplrules_select() with various parameters\n");
78     for ( testItemPtr = testItems; testItemPtr->locale != NULL; ++testItemPtr ) {
79         UErrorCode status = U_ZERO_ERROR;
80         UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status);
81         if ( U_SUCCESS(status) ) {
82             UNumberFormat* unumfmt;
83             UChar keyword[kKeywordBufLen];
84             UChar keywordExpected[kKeywordBufLen];
85             int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status);
86             if (keywdLen >= kKeywordBufLen) {
87                 keyword[kKeywordBufLen-1] = 0;
88             }
89             if ( U_SUCCESS(status) ) {
90                 u_unescape(testItemPtr->keywordExpected, keywordExpected, kKeywordBufLen);
91                 if ( u_strcmp(keyword, keywordExpected) != 0 ) {
92                     char bcharBuf[kKeywordBufLen];
93                     log_data_err("ERROR: uplrules_select for locale %s, number %.1f: expect %s, get %s\n",
94                              testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpected, u_austrcpy(bcharBuf,keyword) );
95                 }
96             } else {
97                 log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
98                         testItemPtr->locale, testItemPtr->number, myErrorName(status) );
99             }
100 
101             status = U_ZERO_ERROR;
102             unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status);
103             if ( U_SUCCESS(status) ) {
104                 keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status);
105                 if (keywdLen >= kKeywordBufLen) {
106                     keyword[kKeywordBufLen-1] = 0;
107                 }
108                 if ( U_SUCCESS(status) ) {
109                     u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen);
110                     if ( u_strcmp(keyword, keywordExpected) != 0 ) {
111                         char bcharBuf[kKeywordBufLen];
112                         log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
113                                  testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) );
114                     }
115                 } else {
116                     log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
117                             testItemPtr->locale, testItemPtr->number, myErrorName(status) );
118                 }
119                 unum_close(unumfmt);
120             } else {
121                 log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
122             }
123 
124             uplrules_close(uplrules);
125         } else {
126             log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
127         }
128     }
129 }
130 
TestOrdinalRules()131 static void TestOrdinalRules() {
132     U_STRING_DECL(two, "two", 3);
133     UChar keyword[8];
134     int32_t length;
135     UErrorCode errorCode = U_ZERO_ERROR;
136     UPluralRules* upr = uplrules_openForType("en", UPLURAL_TYPE_ORDINAL, &errorCode);
137     if (U_FAILURE(errorCode)) {
138         log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode));
139         return;
140     }
141     U_STRING_INIT(two, "two", 3);
142     length = uplrules_select(upr, 2., keyword, 8, &errorCode);
143     if (U_FAILURE(errorCode) || u_strCompare(keyword, length, two, 3, FALSE) != 0) {
144         log_data_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode));
145     }
146     uplrules_close(upr);
147 }
148 
149 /* items for TestGetKeywords */
150 
151 /* all possible plural keywords, in alphabetical order */
152 static const char* knownKeywords[] = {
153     "few",
154     "many",
155     "one",
156     "other",
157     "two",
158     "zero"
159 };
160 enum {
161     kNumKeywords = UPRV_LENGTHOF(knownKeywords)
162 };
163 
164 /* Return the index of keyword in knownKeywords[], or -1 if not found */
getKeywordIndex(const char * keyword)165 static int32_t getKeywordIndex(const char* keyword) {
166     int32_t i, compare;
167     for (i = 0; i < kNumKeywords && (compare = uprv_strcmp(keyword,knownKeywords[i])) >= 0; i++) {
168         if (compare == 0) {
169         	return i;
170         }
171     }
172     return -1;
173 }
174 
175 typedef struct {
176     const char* locale;
177     const char* keywords[kNumKeywords + 1];
178 } KeywordsForLang;
179 
180 static const KeywordsForLang getKeywordsItems[] = {
181     { "zh", { "other" } },
182     { "en", { "one", "other" } },
183     { "fr", { "one", "other" } },
184     { "lv", { "zero", "one", "other" } },
185     { "hr", { "one", "few", "other" } },
186     { "sl", { "one", "two", "few", "other" } },
187     { "he", { "one", "two", "many", "other" } },
188     { "cs", { "one", "few", "many", "other" } },
189     { "ar", { "zero", "one", "two", "few", "many" , "other" } },
190     { NULL, { NULL } }
191 };
192 
TestGetKeywords()193 static void TestGetKeywords() {
194     /*
195      * We don't know the order in which the enumeration will return keywords,
196      * so we have an array with known keywords in a fixed order and then
197      * parallel arrays of flags for expected and actual results that indicate
198      * which keywords are expected to be or actually are found.
199      */
200     const KeywordsForLang* itemPtr = getKeywordsItems;
201     for (; itemPtr->locale != NULL; itemPtr++) {
202         UPluralRules* uplrules;
203         UEnumeration* uenum;
204         UBool expectKeywords[kNumKeywords];
205         UBool getKeywords[kNumKeywords];
206         int32_t i, iKnown;
207         UErrorCode status = U_ZERO_ERROR;
208 
209         /* initialize arrays for expected and get results */
210         for (i = 0; i < kNumKeywords; i++) {
211             expectKeywords[i] = FALSE;
212             getKeywords[i] = FALSE;
213         }
214         for (i = 0; i < kNumKeywords && itemPtr->keywords[i] != NULL; i++) {
215             iKnown = getKeywordIndex(itemPtr->keywords[i]);
216             if (iKnown >= 0) {
217                 expectKeywords[iKnown] = TRUE;
218             }
219         }
220 
221         uplrules = uplrules_openForType(itemPtr->locale, UPLURAL_TYPE_CARDINAL, &status);
222         if (U_FAILURE(status)) {
223             log_err("FAIL: uplrules_openForType for locale %s, UPLURAL_TYPE_CARDINAL: %s\n", itemPtr->locale, myErrorName(status) );
224             continue;
225         }
226         uenum = uplrules_getKeywords(uplrules, &status);
227         if (U_FAILURE(status)) {
228             log_err("FAIL: uplrules_getKeywords for locale %s: %s\n", itemPtr->locale, myErrorName(status) );
229         } else {
230             const char* keyword;
231             int32_t keywordLen, keywordCount = 0;
232             while ((keyword = uenum_next(uenum, &keywordLen, &status)) != NULL && U_SUCCESS(status)) {
233                 iKnown = getKeywordIndex(keyword);
234                 if (iKnown < 0) {
235                     log_err("FAIL: uplrules_getKeywords for locale %s, unknown keyword %s\n", itemPtr->locale, keyword );
236                 } else {
237                     getKeywords[iKnown] = TRUE;
238                 }
239                 keywordCount++;
240             }
241             if (keywordCount > kNumKeywords) {
242                 log_err("FAIL: uplrules_getKeywords for locale %s, got too many keywords %d\n", itemPtr->locale, keywordCount );
243             }
244             if (uprv_memcmp(expectKeywords, getKeywords, kNumKeywords) != 0) {
245                 log_err("FAIL: uplrules_getKeywords for locale %s, got wrong keyword set; with reference to knownKeywords:\n"
246                         "        expected { %d %d %d %d %d %d },\n"
247                         "        got      { %d %d %d %d %d %d }\n", itemPtr->locale,
248                         expectKeywords[0], expectKeywords[1], expectKeywords[2], expectKeywords[3], expectKeywords[4], expectKeywords[5],
249                         getKeywords[0], getKeywords[1], getKeywords[2], getKeywords[3], getKeywords[4], getKeywords[5] );
250             }
251             uenum_close(uenum);
252         }
253 
254         uplrules_close(uplrules);
255     }
256 }
257 
TestFormatted()258 static void TestFormatted() {
259     UErrorCode ec = U_ZERO_ERROR;
260     UNumberFormatter* unumf = NULL;
261     UFormattedNumber* uresult = NULL;
262     UPluralRules* uplrules = NULL;
263 
264     uplrules = uplrules_open("hr", &ec);
265     if (!assertSuccess("open plural rules", &ec)) {
266         goto cleanup;
267     }
268 
269     unumf = unumf_openForSkeletonAndLocale(u".00", -1, "hr", &ec);
270     if (!assertSuccess("open unumf", &ec)) {
271         goto cleanup;
272     }
273 
274     uresult = unumf_openResult(&ec);
275     if (!assertSuccess("open result", &ec)) {
276         goto cleanup;
277     }
278 
279     unumf_formatDouble(unumf, 100.2, uresult, &ec);
280     if (!assertSuccess("format", &ec)) {
281         goto cleanup;
282     }
283 
284     UChar buffer[40];
285     uplrules_selectFormatted(uplrules, uresult, buffer, 40, &ec);
286     if (!assertSuccess("select", &ec)) {
287         goto cleanup;
288     }
289 
290     assertUEquals("0.20 is plural category 'other' in hr", u"other", buffer);
291 
292 cleanup:
293     uplrules_close(uplrules);
294     unumf_close(unumf);
295     unumf_closeResult(uresult);
296 }
297 
298 #endif /* #if !UCONFIG_NO_FORMATTING */
299