1 /********************************************************************
3 * Copyright (c) 2007-2008, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 #include "unicode/utypes.h"
9 #if !UCONFIG_NO_FORMATTING
14 #include "unicode/plurrule.h"
15 #include "unicode/plurfmt.h"
18 const UnicodeString oddAndEvenRule
= UNICODE_STRING_SIMPLE("odd: n mod 2 is 1");
19 #define PLURAL_PATTERN_DATA 4
20 #define PLURAL_TEST_ARRAY_SIZE 256
22 #define PLURAL_SYNTAX_DATA 8
24 // The value must be same as PLKeywordLookups[] order.
32 void PluralFormatTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
34 if (exec
) logln("TestSuite PluralFormat");
36 TESTCASE(0, pluralFormatBasicTest
);
37 TESTCASE(1, pluralFormatUnitTest
);
38 TESTCASE(2, pluralFormatLocaleTest
);
45 * Test various generic API methods of PluralFormat for Basic usage.
47 void PluralFormatTest::pluralFormatBasicTest(/*char *par*/)
50 PluralFormat
* plFmt
[8];
51 Locale locale
= Locale::getDefault();
52 UnicodeString otherPattern
= UnicodeString("other{#}");
53 UnicodeString message
=UnicodeString("ERROR: PluralFormat basic test");
55 // ========= Test constructors
56 logln(" Testing PluralFormat constructors ...");
57 status
[0] = U_ZERO_ERROR
;
58 PluralRules
* plRules
= PluralRules::createDefaultRules(status
[0]);
60 status
[0] = U_ZERO_ERROR
;
61 NumberFormat
*numFmt
= NumberFormat::createInstance(status
[0]);
62 if (U_FAILURE(status
[0])) {
63 dataerrln("ERROR: Could not create NumberFormat instance with default locale ");
66 for (int32_t i
=0; i
< 8; ++i
) {
67 status
[i
] = U_ZERO_ERROR
;
69 plFmt
[0] = new PluralFormat(status
[0]);
70 plFmt
[1] = new PluralFormat(*plRules
, status
[1]);
71 plFmt
[2] = new PluralFormat(locale
, status
[2]);
72 plFmt
[3] = new PluralFormat(locale
, *plRules
, status
[3]);
73 plFmt
[4] = new PluralFormat(otherPattern
, status
[4]);
74 plFmt
[5] = new PluralFormat(*plRules
, otherPattern
, status
[5]);
75 plFmt
[6] = new PluralFormat(locale
, otherPattern
, status
[6]);
76 plFmt
[7] = new PluralFormat(locale
, *plRules
, otherPattern
, status
[7]);
78 for (int32_t i
=0; i
< 8; ++i
) {
79 if (U_SUCCESS(status
[i
])) {
80 numberFormatTest(plFmt
[i
], numFmt
, 1, 12, NULL
, NULL
, FALSE
, &message
);
81 numberFormatTest(plFmt
[i
], numFmt
, 100, 112, NULL
, NULL
, FALSE
, &message
);
84 dataerrln("ERROR: PluralFormat constructor failed!");
88 // ======= Test clone, assignment operator && == operator.
89 plFmt
[0]= new PluralFormat(status
[0]);
90 plFmt
[1]= new PluralFormat(locale
, status
[1]);
91 if ( U_SUCCESS(status
[0]) && U_SUCCESS(status
[1]) ) {
92 *plFmt
[1] = *plFmt
[0];
94 if ( *plFmt
[1] != *plFmt
[0] ) {
95 errln("ERROR: clone plural format test failed!");
100 errln("ERROR: PluralFormat constructor failed!");
102 plFmt
[2]= new PluralFormat(locale
, status
[1]);
103 if ( U_SUCCESS(status
[1]) ) {
104 *plFmt
[1] = *plFmt
[2];
105 if (plFmt
[1]!=NULL
) {
106 if ( *plFmt
[1] != *plFmt
[2] ) {
107 errln("ERROR: assignment operator test failed!");
113 errln("ERROR: PluralFormat constructor failed!");
122 * Unit tests of PluralFormat class.
124 void PluralFormatTest::pluralFormatUnitTest(/*char *par*/)
126 UnicodeString patternTestData
[PLURAL_PATTERN_DATA
] = {
127 UNICODE_STRING_SIMPLE("odd {# is odd.} other{# is even.}"),
128 UNICODE_STRING_SIMPLE("other{# is odd or even.}"),
129 UNICODE_STRING_SIMPLE("odd{The number {0, number, #.#0} is odd.}other{The number {0, number, #.#0} is even.}"),
130 UNICODE_STRING_SIMPLE("odd{The number {#} is odd.}other{The number {#} is even.}"),
132 UnicodeString patternOddTestResult
[PLURAL_PATTERN_DATA
] = {
133 UNICODE_STRING_SIMPLE(" is odd."),
134 UNICODE_STRING_SIMPLE(" is odd or even."),
135 UNICODE_STRING_SIMPLE("The number {0, number, #.#0} is odd."),
136 UNICODE_STRING_SIMPLE("The number {#} is odd."),
138 UnicodeString patternEvenTestResult
[PLURAL_PATTERN_DATA
] = {
139 UNICODE_STRING_SIMPLE(" is even."),
140 UNICODE_STRING_SIMPLE(" is odd or even."),
141 UNICODE_STRING_SIMPLE("The number {0, number, #.#0} is even."),
142 UNICODE_STRING_SIMPLE("The number {#} is even."),
144 UnicodeString checkSyntaxtData
[PLURAL_SYNTAX_DATA
] = {
145 UNICODE_STRING_SIMPLE("odd{foo} odd{bar} other{foobar}"),
146 UNICODE_STRING_SIMPLE("odd{foo} other{bar} other{foobar}"),
147 UNICODE_STRING_SIMPLE("odd{foo}"),
148 UNICODE_STRING_SIMPLE("otto{foo} other{bar}"),
149 UNICODE_STRING_SIMPLE("1odd{foo} other{bar}"),
150 UNICODE_STRING_SIMPLE("odd{foo},other{bar}"),
151 UNICODE_STRING_SIMPLE("od d{foo} other{bar}"),
152 UNICODE_STRING_SIMPLE("odd{foo}{foobar}other{foo}"),
155 UErrorCode status
= U_ZERO_ERROR
;
156 PluralRules
* plRules
= PluralRules::createRules(oddAndEvenRule
, status
);
157 if (U_FAILURE(status
)) {
158 dataerrln("ERROR: create PluralRules instance failed in unit tests.- exitting");
162 // ======= Test PluralRules pattern syntax.
163 logln("Testing PluralRules pattern syntax.");
164 for (int32_t i
=0; i
<PLURAL_SYNTAX_DATA
; ++i
) {
165 status
= U_ZERO_ERROR
;
167 PluralFormat plFmt
=PluralFormat(*plRules
, status
);
168 if (U_FAILURE(status
)) {
169 dataerrln("ERROR: PluralFormat constructor failed in unit tests.- exitting");
172 plFmt
.applyPattern(checkSyntaxtData
[i
], status
);
173 if (U_SUCCESS(status
)) {
174 errln("ERROR: PluralFormat failed to detect syntax error with pattern: "+checkSyntaxtData
[i
]);
180 // ======= Test applying various pattern
181 logln("Testing various patterns");
182 status
= U_ZERO_ERROR
;
183 UBool overwrite
[PLURAL_PATTERN_DATA
] = {FALSE
, FALSE
, TRUE
, TRUE
};
185 NumberFormat
*numFmt
= NumberFormat::createInstance(status
);
186 UnicodeString message
=UnicodeString("ERROR: PluralFormat tests various pattern ...");
187 if (U_FAILURE(status
)) {
188 dataerrln("ERROR: Could not create NumberFormat instance with default locale ");
190 for(int32_t i
=0; i
<PLURAL_PATTERN_DATA
; ++i
) {
191 status
= U_ZERO_ERROR
;
192 PluralFormat plFmt
=PluralFormat(*plRules
, status
);
193 if (U_FAILURE(status
)) {
194 dataerrln("ERROR: PluralFormat constructor failed in unit tests.- exitting");
197 plFmt
.applyPattern(patternTestData
[i
], status
);
198 if (U_FAILURE(status
)) {
199 errln("ERROR: PluralFormat failed to apply pattern- "+patternTestData
[i
]);
202 numberFormatTest(&plFmt
, numFmt
, 1, 10, (UnicodeString
*)&patternOddTestResult
[i
],
203 (UnicodeString
*)&patternEvenTestResult
[i
], overwrite
[i
], &message
);
208 // ======= Test set locale
209 status
= U_ZERO_ERROR
;
210 plRules
= PluralRules::createRules(UNICODE_STRING_SIMPLE("odd: n mod 2 is 1"), status
);
211 PluralFormat pluralFmt
= PluralFormat(*plRules
, status
);
212 if (U_FAILURE(status
)) {
213 dataerrln("ERROR: Could not create PluralFormat instance in setLocale() test - exitting. ");
217 pluralFmt
.applyPattern(UNICODE_STRING_SIMPLE("odd{odd} other{even}"), status
);
218 pluralFmt
.setLocale(Locale::getEnglish(), status
);
219 if (U_FAILURE(status
)) {
220 dataerrln("ERROR: Could not setLocale() with English locale ");
224 message
= UNICODE_STRING_SIMPLE("Error set locale: pattern is not reset!");
226 // Check that pattern gets deleted.
227 logln("\n Test setLocale() ..\n");
228 numFmt
= NumberFormat::createInstance(Locale::getEnglish(), status
);
229 if (U_FAILURE(status
)) {
230 dataerrln("ERROR: Could not create NumberFormat instance with English locale ");
232 numberFormatTest(&pluralFmt
, numFmt
, 5, 5, NULL
, NULL
, FALSE
, &message
);
233 pluralFmt
.applyPattern(UNICODE_STRING_SIMPLE("odd__{odd} other{even}"), status
);
234 if (U_SUCCESS(status
)) {
235 errln("SetLocale should reset rules but did not.");
237 status
= U_ZERO_ERROR
;
238 pluralFmt
.applyPattern(UNICODE_STRING_SIMPLE("one{one} other{not one}"), status
);
239 if (U_FAILURE(status
)) {
240 errln("SetLocale should reset rules but did not.");
242 UnicodeString one
= UNICODE_STRING_SIMPLE("one");
243 UnicodeString notOne
= UNICODE_STRING_SIMPLE("not one");
244 UnicodeString plResult
, numResult
;
245 for (int32_t i
=0; i
<20; ++i
) {
246 plResult
= pluralFmt
.format(i
, status
);
253 if ( numResult
!= plResult
) {
254 errln("Wrong ruleset loaded by setLocale() - got:"+plResult
+ UnicodeString(" expecting:")+numResult
);
258 // =========== Test copy constructor
259 logln("Test copy constructor and == operator of PluralFormat");
260 PluralFormat dupPFmt
= PluralFormat(pluralFmt
);
261 if (pluralFmt
!= dupPFmt
) {
262 errln("Failed in PluralFormat copy constructor or == operator");
272 * Test locale data used in PluralFormat class.
275 PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
277 int8_t pluralResults
[PLURAL_TEST_ARRAY_SIZE
]; // 0: is for default
279 // ======= Test DefaultRule
280 logln("Testing PluralRules with no rule.");
281 const char* oneRuleLocales
[4] = {"ja", "ko", "tr", "vi"};
282 UnicodeString testPattern
= UNICODE_STRING_SIMPLE("other{other}");
283 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
284 pluralResults
[0]= PFT_OTHER
; // other
285 helperTestRusults(oneRuleLocales
, 4, testPattern
, pluralResults
);
287 // ====== Test Singular1 locales.
288 logln("Testing singular1 locales.");
289 const char* singular1Locales
[19] = {"da","de","el","en","eo","es","et","fi",
290 "fo","he","it","nb","nl","nn","no","pt_PT","sv"};
291 testPattern
= UNICODE_STRING_SIMPLE("one{one} other{other}");
292 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
293 pluralResults
[0]= PFT_OTHER
;
294 pluralResults
[1]= PFT_ONE
;
295 pluralResults
[2]= PFT_OTHER
;
296 helperTestRusults(singular1Locales
, 19, testPattern
, pluralResults
);
298 // ======== Test Singular01 locales.
299 logln("Testing singular1 locales.");
300 const char* singular01Locales
[2] = {"fr","pt"};
301 testPattern
= UNICODE_STRING_SIMPLE("one{one} other{other}");
302 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
303 pluralResults
[0]= PFT_ONE
;
304 pluralResults
[2]= PFT_OTHER
;
305 helperTestRusults(singular01Locales
, 2, testPattern
, pluralResults
);
307 // ======== Test ZeroSingular locales.
308 logln("Testing singular1 locales.");
309 const char* zeroSingularLocales
[1] = {"lv"};
310 testPattern
= UNICODE_STRING_SIMPLE("zero{zero} one{one} other{other}");
311 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
312 pluralResults
[0]= PFT_ZERO
;
313 pluralResults
[1]= PFT_ONE
;
314 pluralResults
[2]= PFT_OTHER
;
315 for (int32_t i
=2; i
<20; ++i
) {
317 pluralResults
[i
*10+1] = PFT_ONE
;
318 pluralResults
[i
*10+2] = PFT_OTHER
;
320 helperTestRusults(zeroSingularLocales
, 1, testPattern
, pluralResults
);
322 // ======== Test singular dual locales.
323 logln("Testing singular1 locales.");
324 const char* singularDualLocales
[1] = {"ga"};
325 testPattern
= UNICODE_STRING_SIMPLE("one{one} two{two} other{other}");
326 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
327 pluralResults
[0]= PFT_OTHER
;
328 pluralResults
[1]= PFT_ONE
;
329 pluralResults
[2]= PFT_TWO
;
330 pluralResults
[3]= PFT_OTHER
;
331 helperTestRusults(singularDualLocales
, 1, testPattern
, pluralResults
);
333 // ======== Test Singular Zero Some locales.
334 logln("Testing singular1 locales.");
335 const char* singularZeroSomeLocales
[1] = {"ro"};
336 testPattern
= UNICODE_STRING_SIMPLE("few{few} one{one} other{other}");
337 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
338 pluralResults
[0]= PFT_FEW
;
339 for (int32_t i
=1; i
<20; ++i
) {
341 pluralResults
[i
] = PFT_FEW
;
342 pluralResults
[100+i
] = PFT_FEW
;
344 pluralResults
[1]= PFT_ONE
;
345 helperTestRusults(singularZeroSomeLocales
, 1, testPattern
, pluralResults
);
347 // ======== Test Special 12/19.
348 logln("Testing special 12 and 19.");
349 const char* special12_19Locales
[1] = {"lt"};
350 testPattern
= UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
351 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
352 pluralResults
[0]= PFT_OTHER
;
353 pluralResults
[1]= PFT_ONE
;
354 pluralResults
[2]= PFT_FEW
;
355 pluralResults
[10]= PFT_OTHER
;
356 for (int32_t i
=2; i
<20; ++i
) {
358 pluralResults
[i
*10+1] = PFT_ONE
;
359 pluralResults
[i
*10+2] = PFT_FEW
;
360 pluralResults
[(i
+1)*10] = PFT_OTHER
;
362 helperTestRusults(special12_19Locales
, 1, testPattern
, pluralResults
);
364 // ======== Test Paucal Except 11 14.
365 logln("Testing Paucal Except 11 and 14.");
366 const char* paucal01Locales
[4] = {"hr","ru","sr","uk"};
367 testPattern
= UNICODE_STRING_SIMPLE("one{one} many{many} few{few} other{other}");
368 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
369 pluralResults
[0]= PFT_MANY
;
370 pluralResults
[1]= PFT_ONE
;
371 pluralResults
[2]= PFT_FEW
;
372 pluralResults
[5]= PFT_MANY
;
373 pluralResults
[6]= PFT_MANY
;
374 pluralResults
[7]= PFT_MANY
;
375 pluralResults
[8]= PFT_MANY
;
376 pluralResults
[9]= PFT_MANY
;
377 for (int32_t i
=2; i
<20; ++i
) {
379 pluralResults
[i
*10+1] = PFT_ONE
;
380 pluralResults
[i
*10+2] = PFT_FEW
;
381 pluralResults
[i
*10+5] = PFT_MANY
;
382 pluralResults
[i
*10+6] = PFT_MANY
;
383 pluralResults
[i
*10+7] = PFT_MANY
;
384 pluralResults
[i
*10+8] = PFT_MANY
;
385 pluralResults
[i
*10+9] = PFT_MANY
;
387 helperTestRusults(paucal01Locales
, 4, testPattern
, pluralResults
);
389 // ======== Test Singular Paucal.
390 logln("Testing Singular Paucal.");
391 const char* singularPaucalLocales
[2] = {"cs","sk"};
392 testPattern
= UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
393 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
394 pluralResults
[0]= PFT_OTHER
;
395 pluralResults
[1]= PFT_ONE
;
396 pluralResults
[2]= PFT_FEW
;
397 pluralResults
[5]= PFT_OTHER
;
398 helperTestRusults(singularPaucalLocales
, 2, testPattern
, pluralResults
);
400 // ======== Test Paucal (1), (2,3,4).
401 logln("Testing Paucal (1), (2,3,4).");
402 const char* paucal02Locales
[1] = {"pl"};
403 testPattern
= UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
404 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
405 pluralResults
[0]= PFT_OTHER
;
406 pluralResults
[1]= PFT_ONE
;
407 pluralResults
[5]= PFT_OTHER
;
408 for (int32_t i
=0; i
<20; ++i
) {
409 if ((i
==1)||(i
==2)||(i
==11)||(i
==12)) {
410 pluralResults
[i
*10+2] = PFT_OTHER
;
411 pluralResults
[i
*10+3] = PFT_OTHER
;
412 pluralResults
[i
*10+4] = PFT_OTHER
;
415 pluralResults
[i
*10+2] = PFT_FEW
;
416 pluralResults
[i
*10+3] = PFT_FEW
;
417 pluralResults
[i
*10+4] = PFT_FEW
;
418 pluralResults
[i
*10+5] = PFT_OTHER
;
421 helperTestRusults(paucal02Locales
, 1, testPattern
, pluralResults
);
423 // ======== Test Paucal (1), (2), (3,4).
424 logln("Testing Paucal (1), (2), (3,4).");
425 const char* paucal03Locales
[1] = {"sl"};
426 testPattern
= UNICODE_STRING_SIMPLE("one{one} two{two} few{few} other{other}");
427 uprv_memset(pluralResults
, -1, sizeof(pluralResults
));
428 pluralResults
[0]= PFT_OTHER
;
429 pluralResults
[1]= PFT_ONE
;
430 pluralResults
[2]= PFT_TWO
;
431 pluralResults
[3]= PFT_FEW
;
432 pluralResults
[5]= PFT_OTHER
;
433 pluralResults
[101]= PFT_ONE
;
434 pluralResults
[102]= PFT_TWO
;
435 pluralResults
[103]= PFT_FEW
;
436 pluralResults
[105]= PFT_OTHER
;
437 helperTestRusults(paucal03Locales
, 1, testPattern
, pluralResults
);
439 // TODO: move this test to Unit Test after CLDR 1.6 is final and we support float
440 // ======= Test French "WITHIN rule
441 logln("Testing PluralRules with fr rule.");
442 testPattern
= UNICODE_STRING_SIMPLE("one{one} other{other}");
443 Locale
ulocale((const char *)"fr");
444 UErrorCode status
= U_ZERO_ERROR
;
445 PluralFormat
plFmt(ulocale
, testPattern
, status
);
446 if (U_FAILURE(status
)) {
447 errln("Failed to apply pattern to fr locale");
450 status
= U_ZERO_ERROR
;
451 UnicodeString plResult
= plFmt
.format(0.0, status
); // retrun ONE
452 plResult
= plFmt
.format(0.5, status
); // retrun ONE
453 plResult
= plFmt
.format(1.0, status
); // retrun ONE
454 plResult
= plFmt
.format(1.9, status
); // retrun ONE
455 plResult
= plFmt
.format(2.0, status
); // retrun OTHER
460 PluralFormatTest::numberFormatTest(PluralFormat
* plFmt
,
461 NumberFormat
*numFmt
,
464 UnicodeString
*numOddAppendStr
,
465 UnicodeString
*numEvenAppendStr
,
466 UBool overwrite
, // overwrite the numberFormat.format result
467 UnicodeString
*message
) {
468 UErrorCode status
= U_ZERO_ERROR
;
470 if ( (plFmt
==NULL
) || (numFmt
==NULL
) ) {
471 dataerrln("ERROR: Could not create PluralFormat or NumberFormat - exitting");
474 UnicodeString plResult
, numResult
;
476 for (int32_t i
=start
; i
<= end
; ++i
) {
478 numResult
= numFmt
->format(i
, numResult
);
479 plResult
= plFmt
->format(i
, status
);
480 if ((numOddAppendStr
!= NULL
)&&(numEvenAppendStr
!=NULL
)) {
483 numResult
= *numOddAppendStr
;
486 numResult
= *numEvenAppendStr
;
489 else { // Append the string
491 numResult
+= *numOddAppendStr
;
494 numResult
+= *numEvenAppendStr
;
498 if ( (numResult
!=plResult
) || U_FAILURE(status
) ) {
499 if ( message
== NULL
) {
500 errln("ERROR: Unexpected plural format - got:"+plResult
+ UnicodeString(" expecting:")+numResult
);
503 errln( *message
+UnicodeString(" got:")+plResult
+UnicodeString(" expecting:")+numResult
);
513 PluralFormatTest::helperTestRusults(const char** localeArray
,
514 int32_t capacityOfArray
,
515 UnicodeString
& testPattern
,
516 int8_t *expResults
) {
518 UnicodeString plResult
;
519 const UnicodeString PLKeywordLookups
[6] = {
520 UNICODE_STRING_SIMPLE("zero"),
521 UNICODE_STRING_SIMPLE("one"),
522 UNICODE_STRING_SIMPLE("two"),
523 UNICODE_STRING_SIMPLE("few"),
524 UNICODE_STRING_SIMPLE("many"),
525 UNICODE_STRING_SIMPLE("other"),
528 for (int32_t i
=0; i
<capacityOfArray
; ++i
) {
529 const char *locale
= localeArray
[i
];
530 Locale
ulocale((const char *)locale
);
531 status
= U_ZERO_ERROR
;
532 PluralFormat
plFmt(ulocale
, testPattern
, status
);
533 if (U_FAILURE(status
)) {
534 errln("Failed to apply pattern to locale:"+UnicodeString(localeArray
[i
]));
537 for (int32_t n
=0; n
<PLURAL_TEST_ARRAY_SIZE
; ++n
) {
538 if (expResults
[n
]!=-1) {
539 status
= U_ZERO_ERROR
;
540 plResult
= plFmt
.format(n
, status
);
541 if (U_FAILURE(status
)) {
542 errln("ERROR: Failed to format number in locale data tests with locale: "+
543 UnicodeString(localeArray
[i
]));
545 if (plResult
!= PLKeywordLookups
[expResults
[n
]]){
546 plResult
= plFmt
.format(n
, status
);
547 errln("ERROR: Unexpected format result in locale: "+UnicodeString(localeArray
[i
])+
548 UnicodeString(" got:")+plResult
+ UnicodeString(" expecting:")+
549 PLKeywordLookups
[expResults
[n
]]);
556 #endif /* #if !UCONFIG_NO_FORMATTING */