]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
46f4442e A |
3 | /******************************************************************** |
4 | * COPYRIGHT: | |
2ca993e8 | 5 | * Copyright (c) 2007-2016, International Business Machines Corporation and |
46f4442e A |
6 | * others. All Rights Reserved. |
7 | ********************************************************************/ | |
8 | ||
9 | #include "unicode/utypes.h" | |
10 | ||
11 | #if !UCONFIG_NO_FORMATTING | |
12 | ||
57a6839d A |
13 | #include "unicode/dcfmtsym.h" |
14 | #include "unicode/decimfmt.h" | |
4388f060 | 15 | #include "unicode/msgfmt.h" |
46f4442e | 16 | #include "unicode/plurfmt.h" |
57a6839d A |
17 | #include "unicode/plurrule.h" |
18 | #include "cmemory.h" | |
19 | #include "plurfmts.h" | |
20 | #include "plurults.h" | |
46f4442e | 21 | |
46f4442e A |
22 | #define PLURAL_PATTERN_DATA 4 |
23 | #define PLURAL_TEST_ARRAY_SIZE 256 | |
24 | ||
25 | #define PLURAL_SYNTAX_DATA 8 | |
26 | ||
27 | // The value must be same as PLKeywordLookups[] order. | |
28 | #define PFT_ZERO 0 | |
29 | #define PFT_ONE 1 | |
30 | #define PFT_TWO 2 | |
31 | #define PFT_FEW 3 | |
32 | #define PFT_MANY 4 | |
33 | #define PFT_OTHER 5 | |
34 | ||
35 | void PluralFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) | |
36 | { | |
37 | if (exec) logln("TestSuite PluralFormat"); | |
51004dcb A |
38 | TESTCASE_AUTO_BEGIN; |
39 | TESTCASE_AUTO(pluralFormatBasicTest); | |
40 | TESTCASE_AUTO(pluralFormatUnitTest); | |
41 | TESTCASE_AUTO(pluralFormatLocaleTest); | |
42 | TESTCASE_AUTO(pluralFormatExtendedTest); | |
43 | TESTCASE_AUTO(pluralFormatExtendedParseTest); | |
44 | TESTCASE_AUTO(ordinalFormatTest); | |
57a6839d | 45 | TESTCASE_AUTO(TestDecimals); |
51004dcb | 46 | TESTCASE_AUTO_END; |
46f4442e A |
47 | } |
48 | ||
49 | /** | |
50 | * Test various generic API methods of PluralFormat for Basic usage. | |
51 | */ | |
52 | void PluralFormatTest::pluralFormatBasicTest(/*char *par*/) | |
53 | { | |
54 | UErrorCode status[8]; | |
55 | PluralFormat* plFmt[8]; | |
56 | Locale locale = Locale::getDefault(); | |
57 | UnicodeString otherPattern = UnicodeString("other{#}"); | |
0f5d89e8 | 58 | UnicodeString message=UnicodeString("PluralFormat basic test"); |
46f4442e A |
59 | |
60 | // ========= Test constructors | |
61 | logln(" Testing PluralFormat constructors ..."); | |
62 | status[0] = U_ZERO_ERROR; | |
63 | PluralRules* plRules = PluralRules::createDefaultRules(status[0]); | |
64 | ||
65 | status[0] = U_ZERO_ERROR; | |
66 | NumberFormat *numFmt = NumberFormat::createInstance(status[0]); | |
67 | if (U_FAILURE(status[0])) { | |
68 | dataerrln("ERROR: Could not create NumberFormat instance with default locale "); | |
729e4ab9 | 69 | } |
46f4442e A |
70 | |
71 | for (int32_t i=0; i< 8; ++i) { | |
72 | status[i] = U_ZERO_ERROR; | |
73 | } | |
74 | plFmt[0] = new PluralFormat(status[0]); | |
75 | plFmt[1] = new PluralFormat(*plRules, status[1]); | |
76 | plFmt[2] = new PluralFormat(locale, status[2]); | |
77 | plFmt[3] = new PluralFormat(locale, *plRules, status[3]); | |
78 | plFmt[4] = new PluralFormat(otherPattern, status[4]); | |
79 | plFmt[5] = new PluralFormat(*plRules, otherPattern, status[5]); | |
80 | plFmt[6] = new PluralFormat(locale, otherPattern, status[6]); | |
81 | plFmt[7] = new PluralFormat(locale, *plRules, otherPattern, status[7]); | |
82 | ||
83 | for (int32_t i=0; i< 8; ++i) { | |
84 | if (U_SUCCESS(status[i])) { | |
85 | numberFormatTest(plFmt[i], numFmt, 1, 12, NULL, NULL, FALSE, &message); | |
86 | numberFormatTest(plFmt[i], numFmt, 100, 112, NULL, NULL, FALSE, &message); | |
87 | } | |
88 | else { | |
89 | dataerrln("ERROR: PluralFormat constructor failed!"); | |
90 | } | |
91 | delete plFmt[i]; | |
92 | } | |
93 | // ======= Test clone, assignment operator && == operator. | |
94 | plFmt[0]= new PluralFormat(status[0]); | |
729e4ab9 A |
95 | plFmt[0]->setNumberFormat(numFmt,status[0]); |
96 | UnicodeString us = UnicodeString(""); | |
97 | plFmt[0]->toPattern(us); | |
46f4442e A |
98 | plFmt[1]= new PluralFormat(locale, status[1]); |
99 | if ( U_SUCCESS(status[0]) && U_SUCCESS(status[1]) ) { | |
100 | *plFmt[1] = *plFmt[0]; | |
101 | if (plFmt[1]!=NULL) { | |
102 | if ( *plFmt[1] != *plFmt[0] ) { | |
103 | errln("ERROR: clone plural format test failed!"); | |
104 | } | |
105 | } | |
106 | } | |
107 | else { | |
729e4ab9 | 108 | dataerrln("ERROR: PluralFormat constructor failed! - [0]%s [1]%s", u_errorName(status[0]), u_errorName(status[1])); |
46f4442e | 109 | } |
729e4ab9 A |
110 | delete plFmt[0]; |
111 | ||
112 | status[0] = U_ZERO_ERROR; | |
113 | plFmt[0]= new PluralFormat(locale, status[0]); | |
114 | if ( U_SUCCESS(status[0]) ) { | |
115 | *plFmt[1] = *plFmt[0]; | |
116 | if (plFmt[1]!=NULL) { | |
117 | if ( *plFmt[1] != *plFmt[0] ) { | |
118 | errln("ERROR: assignment operator test failed!"); | |
119 | } | |
120 | } | |
121 | } | |
122 | else { | |
123 | dataerrln("ERROR: PluralFormat constructor failed! - %s", u_errorName(status[1])); | |
124 | } | |
125 | ||
46f4442e | 126 | if ( U_SUCCESS(status[1]) ) { |
729e4ab9 A |
127 | plFmt[2] = (PluralFormat*) plFmt[1]->clone(); |
128 | ||
46f4442e A |
129 | if (plFmt[1]!=NULL) { |
130 | if ( *plFmt[1] != *plFmt[2] ) { | |
729e4ab9 | 131 | errln("ERROR: clone function test failed!"); |
46f4442e A |
132 | } |
133 | } | |
134 | delete plFmt[1]; | |
729e4ab9 | 135 | delete plFmt[2]; |
46f4442e A |
136 | } |
137 | else { | |
729e4ab9 | 138 | dataerrln("ERROR: PluralFormat clone failed! - %s", u_errorName(status[1])); |
46f4442e | 139 | } |
729e4ab9 | 140 | |
46f4442e | 141 | delete plFmt[0]; |
46f4442e A |
142 | delete numFmt; |
143 | delete plRules; | |
729e4ab9 A |
144 | |
145 | // Tests parseObject | |
146 | UErrorCode stat = U_ZERO_ERROR; | |
147 | PluralFormat *pf = new PluralFormat(stat); | |
148 | Formattable *f = new Formattable(); | |
149 | ParsePosition *pp = new ParsePosition(); | |
150 | pf->parseObject((UnicodeString)"",*f,*pp); | |
151 | if(U_FAILURE(stat)) { | |
152 | dataerrln("ERROR: PluralFormat::parseObject: %s", u_errorName(stat)); | |
153 | } | |
154 | delete pf; | |
155 | delete f; | |
156 | delete pp; | |
46f4442e A |
157 | } |
158 | ||
159 | /** | |
160 | * Unit tests of PluralFormat class. | |
161 | */ | |
162 | void PluralFormatTest::pluralFormatUnitTest(/*char *par*/) | |
163 | { | |
164 | UnicodeString patternTestData[PLURAL_PATTERN_DATA] = { | |
165 | UNICODE_STRING_SIMPLE("odd {# is odd.} other{# is even.}"), | |
166 | UNICODE_STRING_SIMPLE("other{# is odd or even.}"), | |
167 | UNICODE_STRING_SIMPLE("odd{The number {0, number, #.#0} is odd.}other{The number {0, number, #.#0} is even.}"), | |
4388f060 | 168 | UNICODE_STRING_SIMPLE("odd{The number {1, number, #} is odd.}other{The number {2, number, #} is even.}"), |
46f4442e A |
169 | }; |
170 | UnicodeString patternOddTestResult[PLURAL_PATTERN_DATA] = { | |
171 | UNICODE_STRING_SIMPLE(" is odd."), | |
172 | UNICODE_STRING_SIMPLE(" is odd or even."), | |
173 | UNICODE_STRING_SIMPLE("The number {0, number, #.#0} is odd."), | |
4388f060 | 174 | UNICODE_STRING_SIMPLE("The number {1, number, #} is odd."), |
46f4442e A |
175 | }; |
176 | UnicodeString patternEvenTestResult[PLURAL_PATTERN_DATA] = { | |
177 | UNICODE_STRING_SIMPLE(" is even."), | |
178 | UNICODE_STRING_SIMPLE(" is odd or even."), | |
179 | UNICODE_STRING_SIMPLE("The number {0, number, #.#0} is even."), | |
4388f060 | 180 | UNICODE_STRING_SIMPLE("The number {2, number, #} is even."), |
46f4442e A |
181 | }; |
182 | UnicodeString checkSyntaxtData[PLURAL_SYNTAX_DATA] = { | |
4388f060 A |
183 | // ICU 4.8 does not check for duplicate keywords any more. |
184 | //UNICODE_STRING_SIMPLE("odd{foo} odd{bar} other{foobar}"), | |
185 | //UNICODE_STRING_SIMPLE("odd{foo} other{bar} other{foobar}"), | |
46f4442e | 186 | UNICODE_STRING_SIMPLE("odd{foo}"), |
4388f060 A |
187 | // ICU 4.8 does not check for unknown keywords any more. |
188 | //UNICODE_STRING_SIMPLE("otto{foo} other{bar}"), | |
189 | UNICODE_STRING_SIMPLE("*odd{foo} other{bar}"), | |
46f4442e A |
190 | UNICODE_STRING_SIMPLE("odd{foo},other{bar}"), |
191 | UNICODE_STRING_SIMPLE("od d{foo} other{bar}"), | |
192 | UNICODE_STRING_SIMPLE("odd{foo}{foobar}other{foo}"), | |
193 | }; | |
194 | ||
195 | UErrorCode status = U_ZERO_ERROR; | |
729e4ab9 | 196 | UnicodeString oddAndEvenRule = UNICODE_STRING_SIMPLE("odd: n mod 2 is 1"); |
46f4442e A |
197 | PluralRules* plRules = PluralRules::createRules(oddAndEvenRule, status); |
198 | if (U_FAILURE(status)) { | |
199 | dataerrln("ERROR: create PluralRules instance failed in unit tests.- exitting"); | |
200 | return; | |
201 | } | |
202 | ||
203 | // ======= Test PluralRules pattern syntax. | |
204 | logln("Testing PluralRules pattern syntax."); | |
205 | for (int32_t i=0; i<PLURAL_SYNTAX_DATA; ++i) { | |
206 | status = U_ZERO_ERROR; | |
207 | ||
208 | PluralFormat plFmt=PluralFormat(*plRules, status); | |
209 | if (U_FAILURE(status)) { | |
210 | dataerrln("ERROR: PluralFormat constructor failed in unit tests.- exitting"); | |
211 | return; | |
212 | } | |
213 | plFmt.applyPattern(checkSyntaxtData[i], status); | |
214 | if (U_SUCCESS(status)) { | |
215 | errln("ERROR: PluralFormat failed to detect syntax error with pattern: "+checkSyntaxtData[i]); | |
216 | } | |
217 | } | |
218 | ||
219 | ||
220 | ||
221 | // ======= Test applying various pattern | |
222 | logln("Testing various patterns"); | |
223 | status = U_ZERO_ERROR; | |
224 | UBool overwrite[PLURAL_PATTERN_DATA] = {FALSE, FALSE, TRUE, TRUE}; | |
225 | ||
226 | NumberFormat *numFmt = NumberFormat::createInstance(status); | |
227 | UnicodeString message=UnicodeString("ERROR: PluralFormat tests various pattern ..."); | |
228 | if (U_FAILURE(status)) { | |
229 | dataerrln("ERROR: Could not create NumberFormat instance with default locale "); | |
230 | } | |
231 | for(int32_t i=0; i<PLURAL_PATTERN_DATA; ++i) { | |
232 | status = U_ZERO_ERROR; | |
233 | PluralFormat plFmt=PluralFormat(*plRules, status); | |
234 | if (U_FAILURE(status)) { | |
235 | dataerrln("ERROR: PluralFormat constructor failed in unit tests.- exitting"); | |
236 | return; | |
237 | } | |
238 | plFmt.applyPattern(patternTestData[i], status); | |
239 | if (U_FAILURE(status)) { | |
240 | errln("ERROR: PluralFormat failed to apply pattern- "+patternTestData[i]); | |
241 | continue; | |
242 | } | |
243 | numberFormatTest(&plFmt, numFmt, 1, 10, (UnicodeString *)&patternOddTestResult[i], | |
244 | (UnicodeString *)&patternEvenTestResult[i], overwrite[i], &message); | |
245 | } | |
246 | delete plRules; | |
247 | delete numFmt; | |
248 | ||
249 | // ======= Test set locale | |
250 | status = U_ZERO_ERROR; | |
251 | plRules = PluralRules::createRules(UNICODE_STRING_SIMPLE("odd: n mod 2 is 1"), status); | |
252 | PluralFormat pluralFmt = PluralFormat(*plRules, status); | |
253 | if (U_FAILURE(status)) { | |
254 | dataerrln("ERROR: Could not create PluralFormat instance in setLocale() test - exitting. "); | |
255 | delete plRules; | |
256 | return; | |
257 | } | |
258 | pluralFmt.applyPattern(UNICODE_STRING_SIMPLE("odd{odd} other{even}"), status); | |
259 | pluralFmt.setLocale(Locale::getEnglish(), status); | |
260 | if (U_FAILURE(status)) { | |
261 | dataerrln("ERROR: Could not setLocale() with English locale "); | |
262 | delete plRules; | |
263 | return; | |
264 | } | |
265 | message = UNICODE_STRING_SIMPLE("Error set locale: pattern is not reset!"); | |
266 | ||
267 | // Check that pattern gets deleted. | |
268 | logln("\n Test setLocale() ..\n"); | |
269 | numFmt = NumberFormat::createInstance(Locale::getEnglish(), status); | |
270 | if (U_FAILURE(status)) { | |
271 | dataerrln("ERROR: Could not create NumberFormat instance with English locale "); | |
272 | } | |
273 | numberFormatTest(&pluralFmt, numFmt, 5, 5, NULL, NULL, FALSE, &message); | |
274 | pluralFmt.applyPattern(UNICODE_STRING_SIMPLE("odd__{odd} other{even}"), status); | |
4388f060 | 275 | if (pluralFmt.format((int32_t)1, status) != UNICODE_STRING_SIMPLE("even")) { |
46f4442e A |
276 | errln("SetLocale should reset rules but did not."); |
277 | } | |
278 | status = U_ZERO_ERROR; | |
279 | pluralFmt.applyPattern(UNICODE_STRING_SIMPLE("one{one} other{not one}"), status); | |
280 | if (U_FAILURE(status)) { | |
281 | errln("SetLocale should reset rules but did not."); | |
282 | } | |
283 | UnicodeString one = UNICODE_STRING_SIMPLE("one"); | |
284 | UnicodeString notOne = UNICODE_STRING_SIMPLE("not one"); | |
285 | UnicodeString plResult, numResult; | |
286 | for (int32_t i=0; i<20; ++i) { | |
287 | plResult = pluralFmt.format(i, status); | |
288 | if ( i==1 ) { | |
289 | numResult = one; | |
290 | } | |
291 | else { | |
292 | numResult = notOne; | |
293 | } | |
294 | if ( numResult != plResult ) { | |
295 | errln("Wrong ruleset loaded by setLocale() - got:"+plResult+ UnicodeString(" expecting:")+numResult); | |
296 | } | |
297 | } | |
298 | ||
299 | // =========== Test copy constructor | |
300 | logln("Test copy constructor and == operator of PluralFormat"); | |
301 | PluralFormat dupPFmt = PluralFormat(pluralFmt); | |
302 | if (pluralFmt != dupPFmt) { | |
303 | errln("Failed in PluralFormat copy constructor or == operator"); | |
304 | } | |
305 | ||
306 | delete plRules; | |
307 | delete numFmt; | |
308 | } | |
309 | ||
310 | ||
311 | ||
312 | /** | |
313 | * Test locale data used in PluralFormat class. | |
314 | */ | |
315 | void | |
316 | PluralFormatTest::pluralFormatLocaleTest(/*char *par*/) | |
317 | { | |
318 | int8_t pluralResults[PLURAL_TEST_ARRAY_SIZE]; // 0: is for default | |
319 | ||
320 | // ======= Test DefaultRule | |
321 | logln("Testing PluralRules with no rule."); | |
57a6839d A |
322 | // for CLDR 24, here delete tr, |
323 | // add id lo ms th zh | |
324 | const char* oneRuleLocales[8] = {"id", "ja", "ko", "lo", "ms", "th", "vi", "zh"}; | |
46f4442e A |
325 | UnicodeString testPattern = UNICODE_STRING_SIMPLE("other{other}"); |
326 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
327 | pluralResults[0]= PFT_OTHER; // other | |
57a6839d | 328 | helperTestResults(oneRuleLocales, 8, testPattern, pluralResults); |
46f4442e A |
329 | |
330 | // ====== Test Singular1 locales. | |
331 | logln("Testing singular1 locales."); | |
57a6839d A |
332 | // for CLDR 24, here delete da de en et fi gl he it nl pt pt sv bn ca gu is mr pa sw ur zu |
333 | // add hu tr others | |
334 | const char* singular1Locales[56] = {"af","asa","az","bem","bez","bg","brx","chr", | |
335 | "ckb","dv","ee","el","eo","es","eu","fo","fur","fy","gsw","ha", | |
336 | "haw","hu","jgo","ka","kk","kl","ks","ku","lb","ml","mn","nah", | |
337 | "nb","ne","nn","no","nr","om","or","pap","ps","rm","rof","sn", | |
338 | "so", "sq","ta","te","tk","tn","tr","ts","vo","wae","xh","xog"}; | |
46f4442e A |
339 | testPattern = UNICODE_STRING_SIMPLE("one{one} other{other}"); |
340 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
341 | pluralResults[0]= PFT_OTHER; | |
342 | pluralResults[1]= PFT_ONE; | |
343 | pluralResults[2]= PFT_OTHER; | |
57a6839d | 344 | helperTestResults(singular1Locales, 56, testPattern, pluralResults); |
46f4442e A |
345 | |
346 | // ======== Test Singular01 locales. | |
347 | logln("Testing singular1 locales."); | |
57a6839d A |
348 | // for CLDR 24, here add hy |
349 | const char* singular01Locales[4] = {"ff","fr","hy","kab"}; | |
46f4442e A |
350 | testPattern = UNICODE_STRING_SIMPLE("one{one} other{other}"); |
351 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
352 | pluralResults[0]= PFT_ONE; | |
353 | pluralResults[2]= PFT_OTHER; | |
57a6839d | 354 | helperTestResults(singular01Locales, 4, testPattern, pluralResults); |
46f4442e A |
355 | |
356 | // ======== Test ZeroSingular locales. | |
357 | logln("Testing singular1 locales."); | |
358 | const char* zeroSingularLocales[1] = {"lv"}; | |
359 | testPattern = UNICODE_STRING_SIMPLE("zero{zero} one{one} other{other}"); | |
360 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
361 | pluralResults[0]= PFT_ZERO; | |
362 | pluralResults[1]= PFT_ONE; | |
46f4442e | 363 | for (int32_t i=2; i<20; ++i) { |
57a6839d A |
364 | pluralResults[i]= (i < 10)? PFT_OTHER: PFT_ZERO; |
365 | pluralResults[i*10] = PFT_ZERO; | |
366 | pluralResults[i*10+1] = PFT_ONE; // note override after loop | |
367 | pluralResults[i*10+2] = PFT_OTHER; // note override after loop | |
46f4442e | 368 | } |
57a6839d A |
369 | pluralResults[111]= PFT_ZERO; |
370 | pluralResults[112]= PFT_ZERO; | |
51004dcb | 371 | helperTestResults(zeroSingularLocales, 1, testPattern, pluralResults); |
46f4442e A |
372 | |
373 | // ======== Test singular dual locales. | |
374 | logln("Testing singular1 locales."); | |
375 | const char* singularDualLocales[1] = {"ga"}; | |
376 | testPattern = UNICODE_STRING_SIMPLE("one{one} two{two} other{other}"); | |
377 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
378 | pluralResults[0]= PFT_OTHER; | |
379 | pluralResults[1]= PFT_ONE; | |
380 | pluralResults[2]= PFT_TWO; | |
381 | pluralResults[3]= PFT_OTHER; | |
51004dcb | 382 | helperTestResults(singularDualLocales, 1, testPattern, pluralResults); |
46f4442e A |
383 | |
384 | // ======== Test Singular Zero Some locales. | |
385 | logln("Testing singular1 locales."); | |
386 | const char* singularZeroSomeLocales[1] = {"ro"}; | |
387 | testPattern = UNICODE_STRING_SIMPLE("few{few} one{one} other{other}"); | |
388 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
389 | pluralResults[0]= PFT_FEW; | |
390 | for (int32_t i=1; i<20; ++i) { | |
57a6839d | 391 | pluralResults[i] = PFT_FEW; // note override after loop |
3d1f044b | 392 | pluralResults[100+i] = PFT_FEW; // note override after loop |
46f4442e A |
393 | } |
394 | pluralResults[1]= PFT_ONE; | |
3d1f044b | 395 | pluralResults[101]= PFT_OTHER; |
51004dcb | 396 | helperTestResults(singularZeroSomeLocales, 1, testPattern, pluralResults); |
46f4442e A |
397 | |
398 | // ======== Test Special 12/19. | |
399 | logln("Testing special 12 and 19."); | |
400 | const char* special12_19Locales[1] = {"lt"}; | |
401 | testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}"); | |
402 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
403 | pluralResults[0]= PFT_OTHER; | |
404 | pluralResults[1]= PFT_ONE; | |
46f4442e | 405 | for (int32_t i=2; i<20; ++i) { |
57a6839d A |
406 | pluralResults[i]= (i < 10)? PFT_FEW: PFT_OTHER; |
407 | pluralResults[i*10] = PFT_OTHER; | |
46f4442e A |
408 | if (i==11) continue; |
409 | pluralResults[i*10+1] = PFT_ONE; | |
410 | pluralResults[i*10+2] = PFT_FEW; | |
46f4442e | 411 | } |
51004dcb | 412 | helperTestResults(special12_19Locales, 1, testPattern, pluralResults); |
46f4442e A |
413 | |
414 | // ======== Test Paucal Except 11 14. | |
57a6839d A |
415 | logln("Testing Paucal Except 11 and 14, set A."); |
416 | const char* paucal01LocalesA[2] = {"hr","sr"}; | |
417 | testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}"); | |
418 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
419 | pluralResults[0]= PFT_OTHER; | |
420 | pluralResults[1]= PFT_ONE; | |
421 | for (int32_t i=2; i<20; ++i) { | |
422 | pluralResults[i]= (i < 5)? PFT_FEW: PFT_OTHER; | |
423 | if (i==11) continue; | |
424 | pluralResults[i*10+1] = PFT_ONE; | |
425 | pluralResults[i*10+2] = PFT_FEW; | |
426 | pluralResults[i*10+5] = PFT_OTHER; | |
427 | pluralResults[i*10+6] = PFT_OTHER; | |
428 | pluralResults[i*10+7] = PFT_OTHER; | |
429 | pluralResults[i*10+8] = PFT_OTHER; | |
430 | pluralResults[i*10+9] = PFT_OTHER; | |
431 | } | |
432 | helperTestResults(paucal01LocalesA, 2, testPattern, pluralResults); | |
433 | ||
434 | logln("Testing Paucal Except 11 and 14, set B."); | |
435 | const char* paucal01LocalesB[1] = {"ru"}; | |
436 | testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} other{other}"); | |
437 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
438 | pluralResults[0]= PFT_MANY; | |
439 | pluralResults[1]= PFT_ONE; | |
440 | for (int32_t i=2; i<20; ++i) { | |
441 | pluralResults[i]= (i < 5)? PFT_OTHER: PFT_MANY; | |
442 | if (i==11) continue; | |
443 | pluralResults[i*10] = PFT_MANY; | |
444 | pluralResults[i*10+1] = PFT_ONE; | |
445 | pluralResults[i*10+2] = PFT_OTHER; | |
446 | pluralResults[i*10+5] = PFT_MANY; | |
447 | pluralResults[i*10+6] = PFT_MANY; | |
448 | pluralResults[i*10+7] = PFT_MANY; | |
449 | pluralResults[i*10+8] = PFT_MANY; | |
450 | pluralResults[i*10+9] = PFT_MANY; | |
451 | } | |
452 | helperTestResults(paucal01LocalesB, 1, testPattern, pluralResults); | |
453 | ||
454 | logln("Testing Paucal Except 11 and 14, set C."); | |
455 | const char* paucal01LocalesC[1] = {"uk"}; | |
46f4442e A |
456 | testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} few{few} other{other}"); |
457 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
458 | pluralResults[0]= PFT_MANY; | |
459 | pluralResults[1]= PFT_ONE; | |
46f4442e | 460 | for (int32_t i=2; i<20; ++i) { |
57a6839d | 461 | pluralResults[i]= (i < 5)? PFT_FEW: PFT_MANY; |
46f4442e | 462 | if (i==11) continue; |
57a6839d | 463 | pluralResults[i*10] = PFT_MANY; |
46f4442e A |
464 | pluralResults[i*10+1] = PFT_ONE; |
465 | pluralResults[i*10+2] = PFT_FEW; | |
466 | pluralResults[i*10+5] = PFT_MANY; | |
467 | pluralResults[i*10+6] = PFT_MANY; | |
468 | pluralResults[i*10+7] = PFT_MANY; | |
469 | pluralResults[i*10+8] = PFT_MANY; | |
470 | pluralResults[i*10+9] = PFT_MANY; | |
471 | } | |
57a6839d | 472 | helperTestResults(paucal01LocalesC, 1, testPattern, pluralResults); |
46f4442e A |
473 | |
474 | // ======== Test Singular Paucal. | |
475 | logln("Testing Singular Paucal."); | |
476 | const char* singularPaucalLocales[2] = {"cs","sk"}; | |
477 | testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}"); | |
478 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
479 | pluralResults[0]= PFT_OTHER; | |
480 | pluralResults[1]= PFT_ONE; | |
481 | pluralResults[2]= PFT_FEW; | |
482 | pluralResults[5]= PFT_OTHER; | |
51004dcb | 483 | helperTestResults(singularPaucalLocales, 2, testPattern, pluralResults); |
46f4442e A |
484 | |
485 | // ======== Test Paucal (1), (2,3,4). | |
486 | logln("Testing Paucal (1), (2,3,4)."); | |
487 | const char* paucal02Locales[1] = {"pl"}; | |
57a6839d | 488 | testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} few{few} other{other}"); |
46f4442e | 489 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); |
46f4442e | 490 | for (int32_t i=0; i<20; ++i) { |
57a6839d A |
491 | pluralResults[i*10+0] = PFT_MANY; |
492 | pluralResults[i*10+1] = PFT_MANY; // note override after loop | |
729e4ab9 | 493 | if ((i==1)||(i==11)) { |
57a6839d A |
494 | pluralResults[i*10+2] = PFT_MANY; |
495 | pluralResults[i*10+3] = PFT_MANY; | |
496 | pluralResults[i*10+4] = PFT_MANY; | |
46f4442e A |
497 | } |
498 | else { | |
499 | pluralResults[i*10+2] = PFT_FEW; | |
500 | pluralResults[i*10+3] = PFT_FEW; | |
501 | pluralResults[i*10+4] = PFT_FEW; | |
46f4442e | 502 | } |
57a6839d | 503 | pluralResults[i*10+5] = PFT_MANY; |
46f4442e | 504 | } |
57a6839d | 505 | pluralResults[1]= PFT_ONE; |
51004dcb | 506 | helperTestResults(paucal02Locales, 1, testPattern, pluralResults); |
46f4442e A |
507 | |
508 | // ======== Test Paucal (1), (2), (3,4). | |
509 | logln("Testing Paucal (1), (2), (3,4)."); | |
510 | const char* paucal03Locales[1] = {"sl"}; | |
511 | testPattern = UNICODE_STRING_SIMPLE("one{one} two{two} few{few} other{other}"); | |
512 | uprv_memset(pluralResults, -1, sizeof(pluralResults)); | |
513 | pluralResults[0]= PFT_OTHER; | |
514 | pluralResults[1]= PFT_ONE; | |
515 | pluralResults[2]= PFT_TWO; | |
516 | pluralResults[3]= PFT_FEW; | |
517 | pluralResults[5]= PFT_OTHER; | |
518 | pluralResults[101]= PFT_ONE; | |
519 | pluralResults[102]= PFT_TWO; | |
520 | pluralResults[103]= PFT_FEW; | |
521 | pluralResults[105]= PFT_OTHER; | |
51004dcb | 522 | helperTestResults(paucal03Locales, 1, testPattern, pluralResults); |
46f4442e A |
523 | |
524 | // TODO: move this test to Unit Test after CLDR 1.6 is final and we support float | |
525 | // ======= Test French "WITHIN rule | |
526 | logln("Testing PluralRules with fr rule."); | |
527 | testPattern = UNICODE_STRING_SIMPLE("one{one} other{other}"); | |
528 | Locale ulocale((const char *)"fr"); | |
529 | UErrorCode status = U_ZERO_ERROR; | |
530 | PluralFormat plFmt(ulocale, testPattern, status); | |
531 | if (U_FAILURE(status)) { | |
729e4ab9 | 532 | dataerrln("Failed to apply pattern to fr locale - %s", u_errorName(status)); |
46f4442e A |
533 | } |
534 | else { | |
535 | status = U_ZERO_ERROR; | |
536 | UnicodeString plResult = plFmt.format(0.0, status); // retrun ONE | |
537 | plResult = plFmt.format(0.5, status); // retrun ONE | |
538 | plResult = plFmt.format(1.0, status); // retrun ONE | |
539 | plResult = plFmt.format(1.9, status); // retrun ONE | |
540 | plResult = plFmt.format(2.0, status); // retrun OTHER | |
541 | } | |
542 | } | |
543 | ||
4388f060 A |
544 | void |
545 | PluralFormatTest::pluralFormatExtendedTest(void) { | |
546 | const char *targets[] = { | |
547 | "There are no widgets.", | |
548 | "There is one widget.", | |
549 | "There is a bling widget and one other widget.", | |
550 | "There is a bling widget and 2 other widgets.", | |
551 | "There is a bling widget and 3 other widgets.", | |
552 | "Widgets, five (5-1=4) there be.", | |
553 | "There is a bling widget and 5 other widgets.", | |
554 | "There is a bling widget and 6 other widgets.", | |
555 | }; | |
556 | ||
557 | const char* fmt = | |
558 | "offset:1.0 " | |
559 | "=0 {There are no widgets.} " | |
560 | "=1.0 {There is one widget.} " | |
561 | "=5 {Widgets, five (5-1=#) there be.} " | |
562 | "one {There is a bling widget and one other widget.} " | |
563 | "other {There is a bling widget and # other widgets.}"; | |
564 | ||
565 | UErrorCode status = U_ZERO_ERROR; | |
566 | UnicodeString fmtString(fmt, -1, US_INV); | |
567 | PluralFormat pf(Locale::getEnglish(), fmtString, status); | |
568 | MessageFormat mf(UNICODE_STRING_SIMPLE("{0,plural,").append(fmtString).append((UChar)0x7d /* '}' */), | |
569 | Locale::getEnglish(), status); | |
570 | Formattable args; | |
571 | FieldPosition ignore; | |
572 | if (U_FAILURE(status)) { | |
573 | dataerrln("Failed to apply pattern - %s", u_errorName(status)); | |
574 | return; | |
575 | } | |
57a6839d | 576 | for (int32_t i = 0; i <= 7; ++i) { |
4388f060 A |
577 | UnicodeString result = pf.format(i, status); |
578 | if (U_FAILURE(status)) { | |
579 | errln("PluralFormat.format(value %d) failed - %s", i, u_errorName(status)); | |
580 | return; | |
581 | } | |
582 | UnicodeString expected(targets[i], -1, US_INV); | |
583 | if (expected != result) { | |
584 | UnicodeString message("PluralFormat.format(): Expected '", -1, US_INV); | |
585 | message.append(expected); | |
586 | message.append(UnicodeString("' but got '", -1, US_INV)); | |
587 | message.append(result); | |
588 | message.append("'", -1, US_INV); | |
589 | errln(message); | |
590 | } | |
591 | args.setLong(i); | |
592 | mf.format(&args, 1, result.remove(), ignore, status); | |
593 | if (U_FAILURE(status)) { | |
594 | errln("MessageFormat.format(value %d) failed - %s", i, u_errorName(status)); | |
595 | return; | |
596 | } | |
597 | if (expected != result) { | |
598 | UnicodeString message("MessageFormat.format(): Expected '", -1, US_INV); | |
599 | message.append(expected); | |
600 | message.append(UnicodeString("' but got '", -1, US_INV)); | |
601 | message.append(result); | |
602 | message.append("'", -1, US_INV); | |
603 | errln(message); | |
604 | } | |
605 | } | |
606 | } | |
607 | ||
608 | void | |
609 | PluralFormatTest::pluralFormatExtendedParseTest(void) { | |
610 | const char *failures[] = { | |
611 | "offset:1..0 =0 {Foo}", | |
612 | "offset:1.0 {Foo}", | |
613 | "=0= {Foo}", | |
614 | "=0 {Foo} =0.0 {Bar}", | |
615 | " = {Foo}", | |
616 | }; | |
2ca993e8 | 617 | int len = UPRV_LENGTHOF(failures); |
4388f060 A |
618 | |
619 | for (int i = 0; i < len; ++i) { | |
620 | UErrorCode status = U_ZERO_ERROR; | |
621 | UnicodeString fmt(failures[i], -1, US_INV); | |
622 | PluralFormat pf(fmt, status); | |
623 | if (U_SUCCESS(status)) { | |
624 | errln("expected failure when parsing '" + fmt + "'"); | |
625 | } | |
626 | } | |
627 | } | |
628 | ||
51004dcb A |
629 | void |
630 | PluralFormatTest::ordinalFormatTest(void) { | |
631 | IcuTestErrorCode errorCode(*this, "ordinalFormatTest"); | |
632 | UnicodeString pattern("one{#st file}two{#nd file}few{#rd file}other{#th file}"); | |
633 | PluralFormat pf(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, pattern, errorCode); | |
0f5d89e8 | 634 | if (errorCode.errDataIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) { |
51004dcb A |
635 | return; |
636 | } | |
637 | UnicodeString result = pf.format((int32_t)321, errorCode); | |
0f5d89e8 | 638 | if (!errorCode.errIfFailureAndReset("PluralFormat.format(321) failed") && |
51004dcb A |
639 | result != UNICODE_STRING_SIMPLE("321st file")) { |
640 | errln(UnicodeString("PluralFormat.format(321) wrong result string: ") + result); | |
641 | } | |
642 | result = pf.format((int32_t)22, errorCode); | |
0f5d89e8 | 643 | if (!errorCode.errIfFailureAndReset("PluralFormat.format(22) failed") && |
51004dcb A |
644 | result != UNICODE_STRING_SIMPLE("22nd file")) { |
645 | errln(UnicodeString("PluralFormat.format(22) wrong result string: ") + result); | |
646 | } | |
647 | result = pf.format((int32_t)3, errorCode); | |
0f5d89e8 | 648 | if (!errorCode.errIfFailureAndReset("PluralFormat.format(3) failed") && |
51004dcb A |
649 | result != UNICODE_STRING_SIMPLE("3rd file")) { |
650 | errln(UnicodeString("PluralFormat.format(3) wrong result string: ") + result); | |
651 | } | |
652 | ||
653 | // Code coverage: Use the other new-for-UPluralType constructor as well. | |
654 | PluralFormat pf2(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, errorCode); | |
655 | pf2.applyPattern(pattern, errorCode); | |
0f5d89e8 | 656 | if (errorCode.errIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) { |
51004dcb A |
657 | return; |
658 | } | |
659 | result = pf2.format((int32_t)456, errorCode); | |
0f5d89e8 | 660 | if (!errorCode.errIfFailureAndReset("PluralFormat.format(456) failed") && |
51004dcb A |
661 | result != UNICODE_STRING_SIMPLE("456th file")) { |
662 | errln(UnicodeString("PluralFormat.format(456) wrong result string: ") + result); | |
663 | } | |
664 | result = pf2.format((int32_t)111, errorCode); | |
0f5d89e8 | 665 | if (!errorCode.errIfFailureAndReset("PluralFormat.format(111) failed") && |
51004dcb A |
666 | result != UNICODE_STRING_SIMPLE("111th file")) { |
667 | errln(UnicodeString("PluralFormat.format(111) wrong result string: ") + result); | |
668 | } | |
669 | } | |
670 | ||
57a6839d A |
671 | void |
672 | PluralFormatTest::TestDecimals() { | |
673 | IcuTestErrorCode errorCode(*this, "TestDecimals"); | |
674 | // Simple number replacement. | |
675 | PluralFormat pf(Locale::getEnglish(), "one{one meter}other{# meters}", errorCode); | |
676 | assertEquals("simple format(1)", "one meter", pf.format((int32_t)1, errorCode), TRUE); | |
677 | assertEquals("simple format(1.5)", "1.5 meters", pf.format(1.5, errorCode), TRUE); | |
678 | PluralFormat pf2(Locale::getEnglish(), | |
679 | "offset:1 one{another meter}other{another # meters}", errorCode); | |
680 | DecimalFormat df("0.0", new DecimalFormatSymbols(Locale::getEnglish(), errorCode), errorCode); | |
681 | pf2.setNumberFormat(&df, errorCode); | |
682 | assertEquals("offset-decimals format(1)", "another 0.0 meters", pf2.format((int32_t)1, errorCode), TRUE); | |
683 | assertEquals("offset-decimals format(2)", "another 1.0 meters", pf2.format((int32_t)2, errorCode), TRUE); | |
684 | assertEquals("offset-decimals format(2.5)", "another 1.5 meters", pf2.format(2.5, errorCode), TRUE); | |
685 | errorCode.reset(); | |
686 | } | |
687 | ||
46f4442e | 688 | void |
0f5d89e8 | 689 | PluralFormatTest::numberFormatTest(PluralFormat* plFmt, |
46f4442e A |
690 | NumberFormat *numFmt, |
691 | int32_t start, | |
692 | int32_t end, | |
693 | UnicodeString *numOddAppendStr, | |
694 | UnicodeString *numEvenAppendStr, | |
695 | UBool overwrite, // overwrite the numberFormat.format result | |
696 | UnicodeString *message) { | |
697 | UErrorCode status = U_ZERO_ERROR; | |
698 | ||
699 | if ( (plFmt==NULL) || (numFmt==NULL) ) { | |
700 | dataerrln("ERROR: Could not create PluralFormat or NumberFormat - exitting"); | |
701 | return; | |
702 | } | |
703 | UnicodeString plResult, numResult ; | |
704 | ||
705 | for (int32_t i=start; i<= end; ++i ) { | |
706 | numResult.remove(); | |
707 | numResult = numFmt->format(i, numResult); | |
708 | plResult = plFmt->format(i, status); | |
709 | if ((numOddAppendStr!= NULL)&&(numEvenAppendStr!=NULL)) { | |
710 | if (overwrite) { | |
711 | if (i&1) { | |
712 | numResult = *numOddAppendStr; | |
713 | } | |
714 | else { | |
715 | numResult = *numEvenAppendStr; | |
716 | } | |
717 | } | |
718 | else { // Append the string | |
719 | if (i&1) { | |
720 | numResult += *numOddAppendStr; | |
721 | } | |
722 | else{ | |
723 | numResult += *numEvenAppendStr; | |
724 | } | |
725 | } | |
726 | } | |
0f5d89e8 A |
727 | if (U_FAILURE(status)) { |
728 | assertSuccess(*message + " in numberFormatTest", status); | |
729 | } | |
730 | if (numResult!=plResult) { | |
46f4442e A |
731 | if ( message == NULL ) { |
732 | errln("ERROR: Unexpected plural format - got:"+plResult+ UnicodeString(" expecting:")+numResult); | |
733 | } | |
734 | else { | |
0f5d89e8 | 735 | assertEquals(*message + " in numberFormatTest", numResult, plResult); |
46f4442e A |
736 | } |
737 | } | |
738 | } | |
739 | return; | |
740 | } | |
741 | ||
742 | ||
743 | void | |
51004dcb | 744 | PluralFormatTest::helperTestResults(const char** localeArray, |
46f4442e A |
745 | int32_t capacityOfArray, |
746 | UnicodeString& testPattern, | |
747 | int8_t *expResults) { | |
748 | UErrorCode status; | |
749 | UnicodeString plResult; | |
750 | const UnicodeString PLKeywordLookups[6] = { | |
751 | UNICODE_STRING_SIMPLE("zero"), | |
752 | UNICODE_STRING_SIMPLE("one"), | |
753 | UNICODE_STRING_SIMPLE("two"), | |
754 | UNICODE_STRING_SIMPLE("few"), | |
755 | UNICODE_STRING_SIMPLE("many"), | |
756 | UNICODE_STRING_SIMPLE("other"), | |
757 | }; | |
758 | ||
759 | for (int32_t i=0; i<capacityOfArray; ++i) { | |
760 | const char *locale = localeArray[i]; | |
761 | Locale ulocale((const char *)locale); | |
762 | status = U_ZERO_ERROR; | |
763 | PluralFormat plFmt(ulocale, testPattern, status); | |
764 | if (U_FAILURE(status)) { | |
729e4ab9 | 765 | dataerrln("Failed to apply pattern to locale:"+UnicodeString(localeArray[i]) + " - " + u_errorName(status)); |
46f4442e A |
766 | continue; |
767 | } | |
768 | for (int32_t n=0; n<PLURAL_TEST_ARRAY_SIZE; ++n) { | |
769 | if (expResults[n]!=-1) { | |
770 | status = U_ZERO_ERROR; | |
771 | plResult = plFmt.format(n, status); | |
772 | if (U_FAILURE(status)) { | |
773 | errln("ERROR: Failed to format number in locale data tests with locale: "+ | |
774 | UnicodeString(localeArray[i])); | |
775 | } | |
776 | if (plResult != PLKeywordLookups[expResults[n]]){ | |
777 | plResult = plFmt.format(n, status); | |
778 | errln("ERROR: Unexpected format result in locale: "+UnicodeString(localeArray[i])+ | |
57a6839d A |
779 | UnicodeString(" for value: ")+n+ |
780 | UnicodeString(" got:")+plResult+ | |
781 | UnicodeString(" expecting:")+ PLKeywordLookups[expResults[n]]); | |
46f4442e A |
782 | } |
783 | } | |
784 | } | |
785 | } | |
786 | } | |
787 | ||
788 | #endif /* #if !UCONFIG_NO_FORMATTING */ |