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 */
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/upluralrules.h"
14 #include "unicode/ustring.h"
15 #include "unicode/uenum.h"
16 #include "unicode/unumberformatter.h"
21 static void TestPluralRules(void);
22 static void TestOrdinalRules(void);
23 static void TestGetKeywords(void);
24 static void TestFormatted(void);
26 void addPluralRulesTest(TestNode
** root
);
28 #define TESTCASE(x) addTest(root, &x, "tsformat/cpluralrulestest/" #x)
30 void addPluralRulesTest(TestNode
** root
)
32 TESTCASE(TestPluralRules
);
33 TESTCASE(TestOrdinalRules
);
34 TESTCASE(TestGetKeywords
);
35 TESTCASE(TestFormatted
);
41 const char * keywordExpected
;
42 const char * keywordExpectedForDecimals
;
43 } PluralRulesTestItem
;
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" },
53 { "pt_PT", 0, "other", "other" },
54 { "pt_PT", 0.5, "other", "other" },
55 { "pt_PT", 1, "one", "other" },
56 { "pt_PT", 1.5, "other", "other" },
57 { "pt_PT", 2, "other", "other" },
59 { "pt_BR", 0, "one", "one" },
60 { "pt_BR", 0.5, "one", "one" },
61 { "pt_BR", 1, "one", "one" },
62 { "pt_BR", 1.5, "one", "one" },
63 { "pt_BR", 2, "other", "other" },
65 { "fr", 0, "one", "one" },
66 { "fr", 0.5, "one", "one" },
67 { "fr", 1, "one", "one" },
68 { "fr", 1.5, "one", "one" },
69 { "fr", 2, "other", "other" },
71 { "ru", 0, "many", "other" },
72 { "ru", 0.5, "other", "other" },
73 { "ru", 1, "one", "other" },
74 { "ru", 1.5, "other", "other" },
75 { "ru", 2, "few", "other" },
76 { "ru", 5, "many", "other" },
77 { "ru", 10, "many", "other" },
78 { "ru", 11, "many", "other" },
80 // ru rules should not be affected by script/lang/keywords <rdar://problem/49268649>
81 { "ru_Cyrl_RU", 0, "many", "other" },
82 { "ru_Cyrl_RU", 0.5, "other", "other" },
83 { "ru_Cyrl_RU", 1, "one", "other" },
84 { "ru_Cyrl_RU", 1.5, "other", "other" },
85 { "ru_Cyrl_RU", 2, "few", "other" },
86 { "ru_Cyrl_RU", 5, "many", "other" },
87 { "ru_Cyrl_RU", 10, "many", "other" },
88 { "ru_Cyrl_RU", 11, "many", "other" },
90 { "ru@numbers=latn", 0, "many", "other" },
91 { "ru@numbers=latn", 0.5, "other", "other" },
92 { "ru@numbers=latn", 1, "one", "other" },
93 { "ru@numbers=latn", 1.5, "other", "other" },
94 { "ru@numbers=latn", 2, "few", "other" },
95 { "ru@numbers=latn", 5, "many", "other" },
96 { "ru@numbers=latn", 10, "many", "other" },
97 { "ru@numbers=latn", 11, "many", "other" },
99 { "ru_Cyrl_RU@numbers=latn", 0, "many", "other" },
100 { "ru_Cyrl_RU@numbers=latn", 0.5, "other", "other" },
101 { "ru_Cyrl_RU@numbers=latn", 1, "one", "other" },
102 { "ru_Cyrl_RU@numbers=latn", 1.5, "other", "other" },
103 { "ru_Cyrl_RU@numbers=latn", 2, "few", "other" },
104 { "ru_Cyrl_RU@numbers=latn", 5, "many", "other" },
105 { "ru_Cyrl_RU@numbers=latn", 10, "many", "other" },
106 { "ru_Cyrl_RU@numbers=latn", 11, "many", "other" },
108 { NULL
, 0, NULL
, NULL
}
111 static const UChar twoDecimalPat
[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
117 static void TestPluralRules()
119 const PluralRulesTestItem
* testItemPtr
;
120 log_verbose("\nTesting uplrules_open() and uplrules_select() with various parameters\n");
121 for ( testItemPtr
= testItems
; testItemPtr
->locale
!= NULL
; ++testItemPtr
) {
122 UErrorCode status
= U_ZERO_ERROR
;
123 UPluralRules
* uplrules
= uplrules_open(testItemPtr
->locale
, &status
);
124 if ( U_SUCCESS(status
) ) {
125 UNumberFormat
* unumfmt
;
126 UChar keyword
[kKeywordBufLen
];
127 UChar keywordExpected
[kKeywordBufLen
];
128 int32_t keywdLen
= uplrules_select(uplrules
, testItemPtr
->number
, keyword
, kKeywordBufLen
, &status
);
129 if (keywdLen
>= kKeywordBufLen
) {
130 keyword
[kKeywordBufLen
-1] = 0;
132 if ( U_SUCCESS(status
) ) {
133 u_unescape(testItemPtr
->keywordExpected
, keywordExpected
, kKeywordBufLen
);
134 if ( u_strcmp(keyword
, keywordExpected
) != 0 ) {
135 char bcharBuf
[kKeywordBufLen
];
136 log_data_err("ERROR: uplrules_select for locale %s, number %.1f: expect %s, get %s\n",
137 testItemPtr
->locale
, testItemPtr
->number
, testItemPtr
->keywordExpected
, u_austrcpy(bcharBuf
,keyword
) );
140 log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
141 testItemPtr
->locale
, testItemPtr
->number
, myErrorName(status
) );
144 status
= U_ZERO_ERROR
;
145 unumfmt
= unum_open(UNUM_PATTERN_DECIMAL
, twoDecimalPat
, -1, testItemPtr
->locale
, NULL
, &status
);
146 if ( U_SUCCESS(status
) ) {
147 keywdLen
= uplrules_selectWithFormat(uplrules
, testItemPtr
->number
, unumfmt
, keyword
, kKeywordBufLen
, &status
);
148 if (keywdLen
>= kKeywordBufLen
) {
149 keyword
[kKeywordBufLen
-1] = 0;
151 if ( U_SUCCESS(status
) ) {
152 u_unescape(testItemPtr
->keywordExpectedForDecimals
, keywordExpected
, kKeywordBufLen
);
153 if ( u_strcmp(keyword
, keywordExpected
) != 0 ) {
154 char bcharBuf
[kKeywordBufLen
];
155 log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
156 testItemPtr
->locale
, testItemPtr
->number
, testItemPtr
->keywordExpectedForDecimals
, u_austrcpy(bcharBuf
,keyword
) );
159 log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
160 testItemPtr
->locale
, testItemPtr
->number
, myErrorName(status
) );
164 log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr
->locale
, myErrorName(status
) );
167 uplrules_close(uplrules
);
169 log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr
->locale
, myErrorName(status
) );
174 static void TestOrdinalRules() {
175 U_STRING_DECL(two
, "two", 3);
178 UErrorCode errorCode
= U_ZERO_ERROR
;
179 UPluralRules
* upr
= uplrules_openForType("en", UPLURAL_TYPE_ORDINAL
, &errorCode
);
180 if (U_FAILURE(errorCode
)) {
181 log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode
));
184 U_STRING_INIT(two
, "two", 3);
185 length
= uplrules_select(upr
, 2., keyword
, 8, &errorCode
);
186 if (U_FAILURE(errorCode
) || u_strCompare(keyword
, length
, two
, 3, FALSE
) != 0) {
187 log_data_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode
));
192 /* items for TestGetKeywords */
194 /* all possible plural keywords, in alphabetical order */
195 static const char* knownKeywords
[] = {
204 kNumKeywords
= UPRV_LENGTHOF(knownKeywords
)
207 /* Return the index of keyword in knownKeywords[], or -1 if not found */
208 static int32_t getKeywordIndex(const char* keyword
) {
210 for (i
= 0; i
< kNumKeywords
&& (compare
= uprv_strcmp(keyword
,knownKeywords
[i
])) >= 0; i
++) {
220 const char* keywords
[kNumKeywords
+ 1];
223 static const KeywordsForLang getKeywordsItems
[] = {
224 { "zh", { "other" } },
225 { "en", { "one", "other" } },
226 { "fr", { "one", "other" } },
227 { "lv", { "zero", "one", "other" } },
228 { "hr", { "one", "few", "other" } },
229 { "sl", { "one", "two", "few", "other" } },
230 { "he", { "one", "two", "many", "other" } },
231 { "cs", { "one", "few", "many", "other" } },
232 { "ar", { "zero", "one", "two", "few", "many" , "other" } },
236 static void TestGetKeywords() {
238 * We don't know the order in which the enumeration will return keywords,
239 * so we have an array with known keywords in a fixed order and then
240 * parallel arrays of flags for expected and actual results that indicate
241 * which keywords are expected to be or actually are found.
243 const KeywordsForLang
* itemPtr
= getKeywordsItems
;
244 for (; itemPtr
->locale
!= NULL
; itemPtr
++) {
245 UPluralRules
* uplrules
;
247 UBool expectKeywords
[kNumKeywords
];
248 UBool getKeywords
[kNumKeywords
];
250 UErrorCode status
= U_ZERO_ERROR
;
252 /* initialize arrays for expected and get results */
253 for (i
= 0; i
< kNumKeywords
; i
++) {
254 expectKeywords
[i
] = FALSE
;
255 getKeywords
[i
] = FALSE
;
257 for (i
= 0; i
< kNumKeywords
&& itemPtr
->keywords
[i
] != NULL
; i
++) {
258 iKnown
= getKeywordIndex(itemPtr
->keywords
[i
]);
260 expectKeywords
[iKnown
] = TRUE
;
264 uplrules
= uplrules_openForType(itemPtr
->locale
, UPLURAL_TYPE_CARDINAL
, &status
);
265 if (U_FAILURE(status
)) {
266 log_err("FAIL: uplrules_openForType for locale %s, UPLURAL_TYPE_CARDINAL: %s\n", itemPtr
->locale
, myErrorName(status
) );
269 uenum
= uplrules_getKeywords(uplrules
, &status
);
270 if (U_FAILURE(status
)) {
271 log_err("FAIL: uplrules_getKeywords for locale %s: %s\n", itemPtr
->locale
, myErrorName(status
) );
274 int32_t keywordLen
, keywordCount
= 0;
275 while ((keyword
= uenum_next(uenum
, &keywordLen
, &status
)) != NULL
&& U_SUCCESS(status
)) {
276 iKnown
= getKeywordIndex(keyword
);
278 log_err("FAIL: uplrules_getKeywords for locale %s, unknown keyword %s\n", itemPtr
->locale
, keyword
);
280 getKeywords
[iKnown
] = TRUE
;
284 if (keywordCount
> kNumKeywords
) {
285 log_err("FAIL: uplrules_getKeywords for locale %s, got too many keywords %d\n", itemPtr
->locale
, keywordCount
);
287 if (uprv_memcmp(expectKeywords
, getKeywords
, kNumKeywords
) != 0) {
288 log_err("FAIL: uplrules_getKeywords for locale %s, got wrong keyword set; with reference to knownKeywords:\n"
289 " expected { %d %d %d %d %d %d },\n"
290 " got { %d %d %d %d %d %d }\n", itemPtr
->locale
,
291 expectKeywords
[0], expectKeywords
[1], expectKeywords
[2], expectKeywords
[3], expectKeywords
[4], expectKeywords
[5],
292 getKeywords
[0], getKeywords
[1], getKeywords
[2], getKeywords
[3], getKeywords
[4], getKeywords
[5] );
297 uplrules_close(uplrules
);
301 static void TestFormatted() {
302 UErrorCode ec
= U_ZERO_ERROR
;
303 UNumberFormatter
* unumf
= NULL
;
304 UFormattedNumber
* uresult
= NULL
;
305 UPluralRules
* uplrules
= NULL
;
307 uplrules
= uplrules_open("hr", &ec
);
308 if (!assertSuccess("open plural rules", &ec
)) {
312 unumf
= unumf_openForSkeletonAndLocale(u
".00", -1, "hr", &ec
);
313 if (!assertSuccess("open unumf", &ec
)) {
317 uresult
= unumf_openResult(&ec
);
318 if (!assertSuccess("open result", &ec
)) {
322 unumf_formatDouble(unumf
, 100.2, uresult
, &ec
);
323 if (!assertSuccess("format", &ec
)) {
328 uplrules_selectFormatted(uplrules
, uresult
, buffer
, 40, &ec
);
329 if (!assertSuccess("select", &ec
)) {
333 assertUEquals("0.20 is plural category 'other' in hr", u
"other", buffer
);
336 uplrules_close(uplrules
);
338 unumf_closeResult(uresult
);
341 #endif /* #if !UCONFIG_NO_FORMATTING */