1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 2007-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9#include "unicode/utypes.h"
10
11#if !UCONFIG_NO_FORMATTING
12
13#include "unicode/dcfmtsym.h"
14#include "unicode/decimfmt.h"
15#include "unicode/msgfmt.h"
16#include "unicode/plurfmt.h"
17#include "unicode/plurrule.h"
18#include "cmemory.h"
19#include "plurfmts.h"
20#include "plurults.h"
21
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
35void PluralFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
36{
37    if (exec) logln("TestSuite PluralFormat");
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);
45    TESTCASE_AUTO(TestDecimals);
46    TESTCASE_AUTO_END;
47}
48
49/**
50 * Test various generic API methods of PluralFormat for Basic usage.
51 */
52void PluralFormatTest::pluralFormatBasicTest(/*char *par*/)
53{
54    UErrorCode status[8];
55    PluralFormat* plFmt[8];
56    Locale        locale = Locale::getDefault();
57    UnicodeString otherPattern = UnicodeString("other{#}");
58    UnicodeString message=UnicodeString("ERROR: PluralFormat basic test");
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 ");
69    }
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]);
95    plFmt[0]->setNumberFormat(numFmt,status[0]);
96    UnicodeString us = UnicodeString("");
97    plFmt[0]->toPattern(us);
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 {
108         dataerrln("ERROR: PluralFormat constructor failed! - [0]%s [1]%s", u_errorName(status[0]), u_errorName(status[1]));
109    }
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
126    if ( U_SUCCESS(status[1]) ) {
127        plFmt[2] = (PluralFormat*) plFmt[1]->clone();
128
129        if (plFmt[1]!=NULL) {
130            if ( *plFmt[1] != *plFmt[2] ) {
131                errln("ERROR:  clone function test failed!");
132            }
133        }
134        delete plFmt[1];
135        delete plFmt[2];
136    }
137    else {
138         dataerrln("ERROR: PluralFormat clone failed! - %s", u_errorName(status[1]));
139    }
140
141    delete plFmt[0];
142    delete numFmt;
143    delete plRules;
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;
157}
158
159/**
160 * Unit tests of PluralFormat class.
161 */
162void 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.}"),
168        UNICODE_STRING_SIMPLE("odd{The number {1, number, #} is odd.}other{The number {2, number, #} is even.}"),
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."),
174        UNICODE_STRING_SIMPLE("The number {1, number, #} is odd."),
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."),
180        UNICODE_STRING_SIMPLE("The number {2, number, #} is even."),
181    };
182    UnicodeString checkSyntaxtData[PLURAL_SYNTAX_DATA] = {
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}"),
186        UNICODE_STRING_SIMPLE("odd{foo}"),
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}"),
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;
196    UnicodeString oddAndEvenRule = UNICODE_STRING_SIMPLE("odd: n mod 2 is 1");
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);
275    if (pluralFmt.format((int32_t)1, status) != UNICODE_STRING_SIMPLE("even")) {
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 */
315void
316PluralFormatTest::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.");
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"};
325    UnicodeString testPattern = UNICODE_STRING_SIMPLE("other{other}");
326    uprv_memset(pluralResults, -1, sizeof(pluralResults));
327    pluralResults[0]= PFT_OTHER; // other
328    helperTestResults(oneRuleLocales, 8, testPattern, pluralResults);
329
330    // ====== Test Singular1 locales.
331    logln("Testing singular1 locales.");
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"};
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;
344    helperTestResults(singular1Locales, 56, testPattern, pluralResults);
345
346    // ======== Test Singular01 locales.
347    logln("Testing singular1 locales.");
348    // for CLDR 24, here add hy
349    const char* singular01Locales[4] = {"ff","fr","hy","kab"};
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;
354    helperTestResults(singular01Locales, 4, testPattern, pluralResults);
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;
363    for (int32_t i=2; i<20; ++i) {
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
368    }
369    pluralResults[111]= PFT_ZERO;
370    pluralResults[112]= PFT_ZERO;
371    helperTestResults(zeroSingularLocales, 1, testPattern, pluralResults);
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;
382    helperTestResults(singularDualLocales, 1, testPattern, pluralResults);
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) {
391        pluralResults[i] = PFT_FEW; // note override after loop
392        pluralResults[100+i] = PFT_FEW;
393    }
394    pluralResults[1]= PFT_ONE;
395    helperTestResults(singularZeroSomeLocales, 1, testPattern, pluralResults);
396
397    // ======== Test Special 12/19.
398    logln("Testing special 12 and 19.");
399    const char* special12_19Locales[1] = {"lt"};
400    testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
401    uprv_memset(pluralResults, -1, sizeof(pluralResults));
402    pluralResults[0]= PFT_OTHER;
403    pluralResults[1]= PFT_ONE;
404    for (int32_t i=2; i<20; ++i) {
405        pluralResults[i]= (i < 10)? PFT_FEW: PFT_OTHER;
406        pluralResults[i*10] = PFT_OTHER;
407        if (i==11)  continue;
408        pluralResults[i*10+1] = PFT_ONE;
409        pluralResults[i*10+2] = PFT_FEW;
410    }
411    helperTestResults(special12_19Locales, 1, testPattern, pluralResults);
412
413    // ======== Test Paucal Except 11 14.
414    logln("Testing Paucal Except 11 and 14, set A.");
415    const char* paucal01LocalesA[2] = {"hr","sr"};
416    testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
417    uprv_memset(pluralResults, -1, sizeof(pluralResults));
418    pluralResults[0]= PFT_OTHER;
419    pluralResults[1]= PFT_ONE;
420    for (int32_t i=2; i<20; ++i) {
421        pluralResults[i]= (i < 5)? PFT_FEW: PFT_OTHER;
422        if (i==11)  continue;
423        pluralResults[i*10+1] = PFT_ONE;
424        pluralResults[i*10+2] = PFT_FEW;
425        pluralResults[i*10+5] = PFT_OTHER;
426        pluralResults[i*10+6] = PFT_OTHER;
427        pluralResults[i*10+7] = PFT_OTHER;
428        pluralResults[i*10+8] = PFT_OTHER;
429        pluralResults[i*10+9] = PFT_OTHER;
430    }
431    helperTestResults(paucal01LocalesA, 2, testPattern, pluralResults);
432
433    logln("Testing Paucal Except 11 and 14, set B.");
434    const char* paucal01LocalesB[1] = {"ru"};
435    testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} other{other}");
436    uprv_memset(pluralResults, -1, sizeof(pluralResults));
437    pluralResults[0]= PFT_MANY;
438    pluralResults[1]= PFT_ONE;
439    for (int32_t i=2; i<20; ++i) {
440        pluralResults[i]= (i < 5)? PFT_OTHER: PFT_MANY;
441        if (i==11)  continue;
442        pluralResults[i*10] = PFT_MANY;
443        pluralResults[i*10+1] = PFT_ONE;
444        pluralResults[i*10+2] = PFT_OTHER;
445        pluralResults[i*10+5] = PFT_MANY;
446        pluralResults[i*10+6] = PFT_MANY;
447        pluralResults[i*10+7] = PFT_MANY;
448        pluralResults[i*10+8] = PFT_MANY;
449        pluralResults[i*10+9] = PFT_MANY;
450    }
451    helperTestResults(paucal01LocalesB, 1, testPattern, pluralResults);
452
453    logln("Testing Paucal Except 11 and 14, set C.");
454    const char* paucal01LocalesC[1] = {"uk"};
455    testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} few{few} other{other}");
456    uprv_memset(pluralResults, -1, sizeof(pluralResults));
457    pluralResults[0]= PFT_MANY;
458    pluralResults[1]= PFT_ONE;
459    for (int32_t i=2; i<20; ++i) {
460        pluralResults[i]= (i < 5)? PFT_FEW: PFT_MANY;
461        if (i==11)  continue;
462        pluralResults[i*10] = PFT_MANY;
463        pluralResults[i*10+1] = PFT_ONE;
464        pluralResults[i*10+2] = PFT_FEW;
465        pluralResults[i*10+5] = PFT_MANY;
466        pluralResults[i*10+6] = PFT_MANY;
467        pluralResults[i*10+7] = PFT_MANY;
468        pluralResults[i*10+8] = PFT_MANY;
469        pluralResults[i*10+9] = PFT_MANY;
470    }
471    helperTestResults(paucal01LocalesC, 1, testPattern, pluralResults);
472
473    // ======== Test Singular Paucal.
474    logln("Testing Singular Paucal.");
475    const char* singularPaucalLocales[2] = {"cs","sk"};
476    testPattern = UNICODE_STRING_SIMPLE("one{one} few{few} other{other}");
477    uprv_memset(pluralResults, -1, sizeof(pluralResults));
478    pluralResults[0]= PFT_OTHER;
479    pluralResults[1]= PFT_ONE;
480    pluralResults[2]= PFT_FEW;
481    pluralResults[5]= PFT_OTHER;
482    helperTestResults(singularPaucalLocales, 2, testPattern, pluralResults);
483
484    // ======== Test Paucal (1), (2,3,4).
485    logln("Testing Paucal (1), (2,3,4).");
486    const char* paucal02Locales[1] = {"pl"};
487    testPattern = UNICODE_STRING_SIMPLE("one{one} many{many} few{few} other{other}");
488    uprv_memset(pluralResults, -1, sizeof(pluralResults));
489    for (int32_t i=0; i<20; ++i) {
490        pluralResults[i*10+0] = PFT_MANY;
491        pluralResults[i*10+1] = PFT_MANY; // note override after loop
492        if ((i==1)||(i==11)) {
493            pluralResults[i*10+2] = PFT_MANY;
494            pluralResults[i*10+3] = PFT_MANY;
495            pluralResults[i*10+4] = PFT_MANY;
496        }
497        else {
498            pluralResults[i*10+2] = PFT_FEW;
499            pluralResults[i*10+3] = PFT_FEW;
500            pluralResults[i*10+4] = PFT_FEW;
501        }
502        pluralResults[i*10+5] = PFT_MANY;
503    }
504    pluralResults[1]= PFT_ONE;
505    helperTestResults(paucal02Locales, 1, testPattern, pluralResults);
506
507    // ======== Test Paucal (1), (2), (3,4).
508    logln("Testing Paucal (1), (2), (3,4).");
509    const char* paucal03Locales[1] = {"sl"};
510    testPattern = UNICODE_STRING_SIMPLE("one{one} two{two} few{few} other{other}");
511    uprv_memset(pluralResults, -1, sizeof(pluralResults));
512    pluralResults[0]= PFT_OTHER;
513    pluralResults[1]= PFT_ONE;
514    pluralResults[2]= PFT_TWO;
515    pluralResults[3]= PFT_FEW;
516    pluralResults[5]= PFT_OTHER;
517    pluralResults[101]= PFT_ONE;
518    pluralResults[102]= PFT_TWO;
519    pluralResults[103]= PFT_FEW;
520    pluralResults[105]= PFT_OTHER;
521    helperTestResults(paucal03Locales, 1, testPattern, pluralResults);
522
523    // TODO: move this test to Unit Test after CLDR 1.6 is final and we support float
524    // ======= Test French "WITHIN rule
525    logln("Testing PluralRules with fr rule.");
526    testPattern = UNICODE_STRING_SIMPLE("one{one} other{other}");
527    Locale ulocale((const char *)"fr");
528    UErrorCode status = U_ZERO_ERROR;
529    PluralFormat plFmt(ulocale, testPattern, status);
530    if (U_FAILURE(status)) {
531        dataerrln("Failed to apply pattern to fr locale - %s", u_errorName(status));
532    }
533    else {
534        status = U_ZERO_ERROR;
535        UnicodeString plResult = plFmt.format(0.0, status);  // retrun ONE
536        plResult = plFmt.format(0.5, status);  // retrun ONE
537        plResult = plFmt.format(1.0, status);  // retrun ONE
538        plResult = plFmt.format(1.9, status);  // retrun ONE
539        plResult = plFmt.format(2.0, status);  // retrun OTHER
540    }
541}
542
543void
544PluralFormatTest::pluralFormatExtendedTest(void) {
545  const char *targets[] = {
546    "There are no widgets.",
547    "There is one widget.",
548    "There is a bling widget and one other widget.",
549    "There is a bling widget and 2 other widgets.",
550    "There is a bling widget and 3 other widgets.",
551    "Widgets, five (5-1=4) there be.",
552    "There is a bling widget and 5 other widgets.",
553    "There is a bling widget and 6 other widgets.",
554  };
555
556  const char* fmt =
557      "offset:1.0 "
558      "=0 {There are no widgets.} "
559      "=1.0 {There is one widget.} "
560      "=5 {Widgets, five (5-1=#) there be.} "
561      "one {There is a bling widget and one other widget.} "
562      "other {There is a bling widget and # other widgets.}";
563
564  UErrorCode status = U_ZERO_ERROR;
565  UnicodeString fmtString(fmt, -1, US_INV);
566  PluralFormat pf(Locale::getEnglish(), fmtString, status);
567  MessageFormat mf(UNICODE_STRING_SIMPLE("{0,plural,").append(fmtString).append((UChar)0x7d /* '}' */),
568                   Locale::getEnglish(), status);
569  Formattable args;
570  FieldPosition ignore;
571  if (U_FAILURE(status)) {
572    dataerrln("Failed to apply pattern - %s", u_errorName(status));
573    return;
574  }
575  for (int32_t i = 0; i <= 7; ++i) {
576    UnicodeString result = pf.format(i, status);
577    if (U_FAILURE(status)) {
578      errln("PluralFormat.format(value %d) failed - %s", i, u_errorName(status));
579      return;
580    }
581    UnicodeString expected(targets[i], -1, US_INV);
582    if (expected != result) {
583      UnicodeString message("PluralFormat.format(): Expected '", -1, US_INV);
584      message.append(expected);
585      message.append(UnicodeString("' but got '", -1, US_INV));
586      message.append(result);
587      message.append("'", -1, US_INV);
588      errln(message);
589    }
590    args.setLong(i);
591    mf.format(&args, 1, result.remove(), ignore, status);
592    if (U_FAILURE(status)) {
593      errln("MessageFormat.format(value %d) failed - %s", i, u_errorName(status));
594      return;
595    }
596    if (expected != result) {
597      UnicodeString message("MessageFormat.format(): Expected '", -1, US_INV);
598      message.append(expected);
599      message.append(UnicodeString("' but got '", -1, US_INV));
600      message.append(result);
601      message.append("'", -1, US_INV);
602      errln(message);
603    }
604  }
605}
606
607void
608PluralFormatTest::pluralFormatExtendedParseTest(void) {
609  const char *failures[] = {
610    "offset:1..0 =0 {Foo}",
611    "offset:1.0 {Foo}",
612    "=0= {Foo}",
613    "=0 {Foo} =0.0 {Bar}",
614    " = {Foo}",
615  };
616  int len = UPRV_LENGTHOF(failures);
617
618  for (int i = 0; i < len; ++i) {
619    UErrorCode status = U_ZERO_ERROR;
620    UnicodeString fmt(failures[i], -1, US_INV);
621    PluralFormat pf(fmt, status);
622    if (U_SUCCESS(status)) {
623      errln("expected failure when parsing '" + fmt + "'");
624    }
625  }
626}
627
628void
629PluralFormatTest::ordinalFormatTest(void) {
630    IcuTestErrorCode errorCode(*this, "ordinalFormatTest");
631    UnicodeString pattern("one{#st file}two{#nd file}few{#rd file}other{#th file}");
632    PluralFormat pf(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, pattern, errorCode);
633    if (errorCode.logDataIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) {
634      return;
635    }
636    UnicodeString result = pf.format((int32_t)321, errorCode);
637    if (!errorCode.logIfFailureAndReset("PluralFormat.format(321) failed") &&
638        result != UNICODE_STRING_SIMPLE("321st file")) {
639      errln(UnicodeString("PluralFormat.format(321) wrong result string: ") + result);
640    }
641    result = pf.format((int32_t)22, errorCode);
642    if (!errorCode.logIfFailureAndReset("PluralFormat.format(22) failed") &&
643        result != UNICODE_STRING_SIMPLE("22nd file")) {
644      errln(UnicodeString("PluralFormat.format(22) wrong result string: ") + result);
645    }
646    result = pf.format((int32_t)3, errorCode);
647    if (!errorCode.logIfFailureAndReset("PluralFormat.format(3) failed") &&
648        result != UNICODE_STRING_SIMPLE("3rd file")) {
649      errln(UnicodeString("PluralFormat.format(3) wrong result string: ") + result);
650    }
651
652    // Code coverage: Use the other new-for-UPluralType constructor as well.
653    PluralFormat pf2(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, errorCode);
654    pf2.applyPattern(pattern, errorCode);
655    if (errorCode.logIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) {
656      return;
657    }
658    result = pf2.format((int32_t)456, errorCode);
659    if (!errorCode.logIfFailureAndReset("PluralFormat.format(456) failed") &&
660        result != UNICODE_STRING_SIMPLE("456th file")) {
661      errln(UnicodeString("PluralFormat.format(456) wrong result string: ") + result);
662    }
663    result = pf2.format((int32_t)111, errorCode);
664    if (!errorCode.logIfFailureAndReset("PluralFormat.format(111) failed") &&
665        result != UNICODE_STRING_SIMPLE("111th file")) {
666      errln(UnicodeString("PluralFormat.format(111) wrong result string: ") + result);
667    }
668}
669
670void
671PluralFormatTest::TestDecimals() {
672    IcuTestErrorCode errorCode(*this, "TestDecimals");
673    // Simple number replacement.
674    PluralFormat pf(Locale::getEnglish(), "one{one meter}other{# meters}", errorCode);
675    assertEquals("simple format(1)", "one meter", pf.format((int32_t)1, errorCode), TRUE);
676    assertEquals("simple format(1.5)", "1.5 meters", pf.format(1.5, errorCode), TRUE);
677    PluralFormat pf2(Locale::getEnglish(),
678            "offset:1 one{another meter}other{another # meters}", errorCode);
679    DecimalFormat df("0.0", new DecimalFormatSymbols(Locale::getEnglish(), errorCode), errorCode);
680    pf2.setNumberFormat(&df, errorCode);
681    assertEquals("offset-decimals format(1)", "another 0.0 meters", pf2.format((int32_t)1, errorCode), TRUE);
682    assertEquals("offset-decimals format(2)", "another 1.0 meters", pf2.format((int32_t)2, errorCode), TRUE);
683    assertEquals("offset-decimals format(2.5)", "another 1.5 meters", pf2.format(2.5, errorCode), TRUE);
684    errorCode.reset();
685}
686
687void
688PluralFormatTest::numberFormatTest(PluralFormat* plFmt,
689                                   NumberFormat *numFmt,
690                                   int32_t start,
691                                   int32_t end,
692                                   UnicodeString *numOddAppendStr,
693                                   UnicodeString *numEvenAppendStr,
694                                   UBool overwrite,  // overwrite the numberFormat.format result
695                                   UnicodeString *message) {
696    UErrorCode status = U_ZERO_ERROR;
697
698    if ( (plFmt==NULL) || (numFmt==NULL) ) {
699        dataerrln("ERROR: Could not create PluralFormat or NumberFormat - exitting");
700        return;
701    }
702    UnicodeString plResult, numResult ;
703
704    for (int32_t i=start; i<= end; ++i ) {
705        numResult.remove();
706        numResult = numFmt->format(i, numResult);
707        plResult = plFmt->format(i, status);
708        if ((numOddAppendStr!= NULL)&&(numEvenAppendStr!=NULL)) {
709            if (overwrite) {
710                if (i&1) {
711                    numResult = *numOddAppendStr;
712                }
713                else {
714                    numResult = *numEvenAppendStr;
715                }
716            }
717            else {  // Append the string
718                if (i&1) {
719                    numResult += *numOddAppendStr;
720                }
721                else{
722                    numResult += *numEvenAppendStr;
723                }
724            }
725        }
726        if ( (numResult!=plResult) || U_FAILURE(status) ) {
727            if ( message == NULL ) {
728                errln("ERROR: Unexpected plural format - got:"+plResult+ UnicodeString("  expecting:")+numResult);
729            }
730            else {
731                errln( *message+UnicodeString("  got:")+plResult+UnicodeString("  expecting:")+numResult);
732            }
733        }
734    }
735    return;
736}
737
738
739void
740PluralFormatTest::helperTestResults(const char** localeArray,
741                                    int32_t capacityOfArray,
742                                    UnicodeString& testPattern,
743                                    int8_t *expResults) {
744    UErrorCode status;
745    UnicodeString plResult;
746    const UnicodeString PLKeywordLookups[6] = {
747        UNICODE_STRING_SIMPLE("zero"),
748        UNICODE_STRING_SIMPLE("one"),
749        UNICODE_STRING_SIMPLE("two"),
750        UNICODE_STRING_SIMPLE("few"),
751        UNICODE_STRING_SIMPLE("many"),
752        UNICODE_STRING_SIMPLE("other"),
753    };
754
755    for (int32_t i=0; i<capacityOfArray; ++i) {
756        const char *locale = localeArray[i];
757        Locale ulocale((const char *)locale);
758        status = U_ZERO_ERROR;
759        PluralFormat plFmt(ulocale, testPattern, status);
760        if (U_FAILURE(status)) {
761            dataerrln("Failed to apply pattern to locale:"+UnicodeString(localeArray[i]) + " - " + u_errorName(status));
762            continue;
763        }
764        for (int32_t n=0; n<PLURAL_TEST_ARRAY_SIZE; ++n) {
765            if (expResults[n]!=-1) {
766                status = U_ZERO_ERROR;
767                plResult = plFmt.format(n, status);
768                if (U_FAILURE(status)) {
769                    errln("ERROR: Failed to format number in locale data tests with locale: "+
770                           UnicodeString(localeArray[i]));
771                }
772                if (plResult != PLKeywordLookups[expResults[n]]){
773                    plResult = plFmt.format(n, status);
774                    errln("ERROR: Unexpected format result in locale: "+UnicodeString(localeArray[i])+
775                          UnicodeString(" for value: ")+n+
776                          UnicodeString("  got:")+plResult+
777                          UnicodeString("  expecting:")+ PLKeywordLookups[expResults[n]]);
778                }
779            }
780        }
781    }
782}
783
784#endif /* #if !UCONFIG_NO_FORMATTING */
785