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