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 35 void 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 */ 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{#}"); 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 */ 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.}"), 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 */ 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."); 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 543 void 544 PluralFormatTest::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 607 void 608 PluralFormatTest::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 628 void 629 PluralFormatTest::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 670 void 671 PluralFormatTest::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 687 void 688 PluralFormatTest::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 739 void 740 PluralFormatTest::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