1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2015, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ******************************************************************** 6 * File TMSGFMT.CPP 7 * 8 * Modification History: 9 * 10 * Date Name Description 11 * 03/24/97 helena Converted from Java. 12 * 07/11/97 helena Updated to work on AIX. 13 * 08/04/97 jfitz Updated to intltest 14 *******************************************************************/ 15 16 #include "unicode/utypes.h" 17 18 #if !UCONFIG_NO_FORMATTING 19 20 #include "tmsgfmt.h" 21 #include "cmemory.h" 22 23 #include "unicode/format.h" 24 #include "unicode/decimfmt.h" 25 #include "unicode/localpointer.h" 26 #include "unicode/locid.h" 27 #include "unicode/msgfmt.h" 28 #include "unicode/numfmt.h" 29 #include "unicode/choicfmt.h" 30 #include "unicode/messagepattern.h" 31 #include "unicode/selfmt.h" 32 #include "unicode/gregocal.h" 33 #include <stdio.h> 34 35 void 36 TestMessageFormat::runIndexedTest(int32_t index, UBool exec, 37 const char* &name, char* /*par*/) { 38 TESTCASE_AUTO_BEGIN; 39 TESTCASE_AUTO(testBug1); 40 TESTCASE_AUTO(testBug2); 41 TESTCASE_AUTO(sample); 42 TESTCASE_AUTO(PatternTest); 43 TESTCASE_AUTO(testStaticFormat); 44 TESTCASE_AUTO(testSimpleFormat); 45 TESTCASE_AUTO(testMsgFormatChoice); 46 TESTCASE_AUTO(testCopyConstructor); 47 TESTCASE_AUTO(testAssignment); 48 TESTCASE_AUTO(testClone); 49 TESTCASE_AUTO(testEquals); 50 TESTCASE_AUTO(testNotEquals); 51 TESTCASE_AUTO(testSetLocale); 52 TESTCASE_AUTO(testFormat); 53 TESTCASE_AUTO(testParse); 54 TESTCASE_AUTO(testAdopt); 55 TESTCASE_AUTO(testCopyConstructor2); 56 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats); 57 TESTCASE_AUTO(TestRBNF); 58 TESTCASE_AUTO(TestTurkishCasing); 59 TESTCASE_AUTO(testAutoQuoteApostrophe); 60 TESTCASE_AUTO(testMsgFormatPlural); 61 TESTCASE_AUTO(testMsgFormatSelect); 62 TESTCASE_AUTO(testApostropheInPluralAndSelect); 63 TESTCASE_AUTO(TestApostropheMode); 64 TESTCASE_AUTO(TestCompatibleApostrophe); 65 TESTCASE_AUTO(testCoverage); 66 TESTCASE_AUTO(testGetFormatNames); 67 TESTCASE_AUTO(TestTrimArgumentName); 68 TESTCASE_AUTO(TestSelectOrdinal); 69 TESTCASE_AUTO(TestDecimals); 70 TESTCASE_AUTO_END; 71 } 72 73 void TestMessageFormat::testBug3() 74 { 75 double myNumber = -123456; 76 DecimalFormat *form = 0; 77 Locale locale[] = { 78 Locale("ar", "", ""), 79 Locale("be", "", ""), 80 Locale("bg", "", ""), 81 Locale("ca", "", ""), 82 Locale("cs", "", ""), 83 Locale("da", "", ""), 84 Locale("de", "", ""), 85 Locale("de", "AT", ""), 86 Locale("de", "CH", ""), 87 Locale("el", "", ""), // 10 88 Locale("en", "CA", ""), 89 Locale("en", "GB", ""), 90 Locale("en", "IE", ""), 91 Locale("en", "US", ""), 92 Locale("es", "", ""), 93 Locale("et", "", ""), 94 Locale("fi", "", ""), 95 Locale("fr", "", ""), 96 Locale("fr", "BE", ""), 97 Locale("fr", "CA", ""), // 20 98 Locale("fr", "CH", ""), 99 Locale("he", "", ""), 100 Locale("hr", "", ""), 101 Locale("hu", "", ""), 102 Locale("is", "", ""), 103 Locale("it", "", ""), 104 Locale("it", "CH", ""), 105 Locale("ja", "", ""), 106 Locale("ko", "", ""), 107 Locale("lt", "", ""), // 30 108 Locale("lv", "", ""), 109 Locale("mk", "", ""), 110 Locale("nl", "", ""), 111 Locale("nl", "BE", ""), 112 Locale("no", "", ""), 113 Locale("pl", "", ""), 114 Locale("pt", "", ""), 115 Locale("ro", "", ""), 116 Locale("ru", "", ""), 117 Locale("sh", "", ""), // 40 118 Locale("sk", "", ""), 119 Locale("sl", "", ""), 120 Locale("sq", "", ""), 121 Locale("sr", "", ""), 122 Locale("sv", "", ""), 123 Locale("tr", "", ""), 124 Locale("uk", "", ""), 125 Locale("zh", "", ""), 126 Locale("zh", "TW", "") // 49 127 }; 128 int32_t i; 129 for (i= 0; i < 49; i++) { 130 UnicodeString buffer; 131 logln(locale[i].getDisplayName(buffer)); 132 UErrorCode success = U_ZERO_ERROR; 133 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success); 134 form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success); 135 if (U_FAILURE(success)) { 136 errln("Err: Number Format "); 137 logln("Number format creation failed."); 138 continue; 139 } 140 Formattable result; 141 FieldPosition pos(0); 142 buffer.remove(); 143 form->format(myNumber, buffer, pos); 144 success = U_ZERO_ERROR; 145 ParsePosition parsePos; 146 form->parse(buffer, result, parsePos); 147 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]")); 148 if (U_FAILURE(success)) { 149 errln("Err: Number Format parse"); 150 logln("Number format parse failed."); 151 } 152 delete form; 153 } 154 } 155 156 void TestMessageFormat::testBug1() 157 { 158 const double limit[] = {0.0, 1.0, 2.0}; 159 const UnicodeString formats[] = {"0.0<=Arg<1.0", 160 "1.0<=Arg<2.0", 161 "2.0<-Arg"}; 162 ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3); 163 FieldPosition status(0); 164 UnicodeString toAppendTo; 165 cf->format((int32_t)1, toAppendTo, status); 166 if (toAppendTo != "1.0<=Arg<2.0") { 167 errln("ChoiceFormat cmp in testBug1"); 168 } 169 logln(toAppendTo); 170 delete cf; 171 } 172 173 void TestMessageFormat::testBug2() 174 { 175 UErrorCode status = U_ZERO_ERROR; 176 UnicodeString result; 177 // {sfb} use double format in pattern, so result will match (not strictly necessary) 178 const UnicodeString pattern = "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. "; 179 logln("The input pattern : " + pattern); 180 MessageFormat *fmt = new MessageFormat(pattern, status); 181 if (U_FAILURE(status)) { 182 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status)); 183 return; 184 } 185 logln("The output pattern is : " + fmt->toPattern(result)); 186 if (pattern != result) { 187 errln("MessageFormat::toPattern() failed."); 188 } 189 delete fmt; 190 } 191 192 #if 0 193 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 194 //---------------------------------------------------- 195 // console I/O 196 //---------------------------------------------------- 197 198 #include <iostream> 199 std::ostream& operator<<(std::ostream& stream, const Formattable& obj); 200 201 #include "unicode/datefmt.h" 202 #include <stdlib.h> 203 #include <string.h> 204 205 IntlTest& 206 operator<<( IntlTest& stream, 207 const Formattable& obj) 208 { 209 static DateFormat *defDateFormat = 0; 210 211 UnicodeString buffer; 212 switch(obj.getType()) { 213 case Formattable::kDate : 214 if (defDateFormat == 0) { 215 defDateFormat = DateFormat::createInstance(); 216 } 217 defDateFormat->format(obj.getDate(), buffer); 218 stream << buffer; 219 break; 220 case Formattable::kDouble : 221 char convert[20]; 222 sprintf( convert, "%lf", obj.getDouble() ); 223 stream << convert << "D"; 224 break; 225 case Formattable::kLong : 226 stream << obj.getLong() << "L"; 227 break; 228 case Formattable::kString: 229 stream << "\"" << obj.getString(buffer) << "\""; 230 break; 231 case Formattable::kArray: 232 int32_t i, count; 233 const Formattable* array; 234 array = obj.getArray(count); 235 stream << "["; 236 for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " ); 237 stream << "]"; 238 break; 239 default: 240 stream << "INVALID_Formattable"; 241 } 242 return stream; 243 } 244 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */ 245 #endif 246 247 void TestMessageFormat::PatternTest() 248 { 249 Formattable testArgs[] = { 250 Formattable(double(1)), Formattable(double(3456)), 251 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate) 252 }; 253 UnicodeString testCases[] = { 254 "Quotes '', '{', 'a' {0} '{0}'", 255 "Quotes '', '{', 'a' {0,number} '{0}'", 256 "'{'1,number,'#',##} {1,number,'#',##}", 257 "There are {1} files on {2} at {3}.", 258 "On {2}, there are {1} files, with {0,number,currency}.", 259 "'{1,number,percent}', {1,number,percent},", 260 "'{1,date,full}', {1,date,full},", 261 "'{3,date,full}', {3,date,full},", 262 "'{1,number,#,##}' {1,number,#,##}", 263 }; 264 265 // ICU 4.8 returns the original pattern (testCases), 266 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). 267 /*UnicodeString testResultPatterns[] = { 268 "Quotes '', '{', a {0} '{'0}", 269 "Quotes '', '{', a {0,number} '{'0}", 270 "'{'1,number,#,##} {1,number,'#'#,##}", 271 "There are {1} files on {2} at {3}.", 272 "On {2}, there are {1} files, with {0,number,currency}.", 273 "'{'1,number,percent}, {1,number,percent},", 274 "'{'1,date,full}, {1,date,full},", 275 "'{'3,date,full}, {3,date,full},", 276 "'{'1,number,#,##} {1,number,#,##}" 277 };*/ 278 279 UnicodeString testResultStrings[] = { 280 "Quotes ', {, 'a' 1 {0}", 281 "Quotes ', {, 'a' 1 {0}", 282 "{1,number,'#',##} #34,56", 283 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.", 284 "On Disk, there are 3,456 files, with $1.00.", 285 "{1,number,percent}, 345,600%,", 286 "{1,date,full}, Wednesday, December 31, 1969,", 287 "{3,date,full}, Monday, January 12, 1970,", 288 "{1,number,#,##} 34,56" 289 }; 290 291 292 for (int32_t i = 0; i < 9; ++i) { 293 //it_out << "\nPat in: " << testCases[i]); 294 295 MessageFormat *form = 0; 296 UErrorCode success = U_ZERO_ERROR; 297 UnicodeString buffer; 298 form = new MessageFormat(testCases[i], Locale::getUS(), success); 299 if (U_FAILURE(success)) { 300 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success)); 301 logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n"); 302 continue; 303 } 304 // ICU 4.8 returns the original pattern (testCases), 305 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). 306 if (form->toPattern(buffer) != testCases[i]) { 307 // Note: An alternative test would be to build MessagePattern objects for 308 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc. 309 // into account. 310 // (Too much trouble...) 311 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i); 312 //form->toPattern(buffer); 313 errln(((UnicodeString)" Orig: ") + testCases[i]); 314 errln(((UnicodeString)" Exp: ") + testCases[i]); 315 errln(((UnicodeString)" Got: ") + buffer); 316 } 317 318 //it_out << "Pat out: " << form->toPattern(buffer)); 319 UnicodeString result; 320 int32_t count = 4; 321 FieldPosition fieldpos(0); 322 form->format(testArgs, count, result, fieldpos, success); 323 if (U_FAILURE(success)) { 324 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success)); 325 logln("TestMessageFormat::PatternTest failed test #3"); 326 continue; 327 } 328 if (result != testResultStrings[i]) { 329 errln("TestMessageFormat::PatternTest failed test #4"); 330 logln("TestMessageFormat::PatternTest failed #4."); 331 logln(UnicodeString(" Result: ") + result ); 332 logln(UnicodeString(" Expected: ") + testResultStrings[i] ); 333 } 334 335 336 //it_out << "Result: " << result); 337 #if 0 338 /* TODO: Look at this test and see if this is still a valid test */ 339 logln("---------------- test parse ----------------"); 340 341 form->toPattern(buffer); 342 logln("MSG pattern for parse: " + buffer); 343 344 int32_t parseCount = 0; 345 Formattable* values = form->parse(result, parseCount, success); 346 if (U_FAILURE(success)) { 347 errln("MessageFormat failed test #5"); 348 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success); 349 } else if (parseCount != count) { 350 errln("MSG count not %d as expected. Got %d", count, parseCount); 351 } 352 UBool failed = FALSE; 353 for (int32_t j = 0; j < parseCount; ++j) { 354 if (values == 0 || testArgs[j] != values[j]) { 355 errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j])); 356 errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j])); 357 failed = TRUE; 358 } 359 } 360 if (failed) 361 errln("MessageFormat failed test #6"); 362 #endif 363 delete form; 364 } 365 } 366 367 void TestMessageFormat::sample() 368 { 369 MessageFormat *form = 0; 370 UnicodeString buffer1, buffer2; 371 UErrorCode success = U_ZERO_ERROR; 372 form = new MessageFormat("There are {0} files on {1}", success); 373 if (U_FAILURE(success)) { 374 errln("Err: Message format creation failed"); 375 logln("Sample message format creation failed."); 376 return; 377 } 378 UnicodeString abc("abc"); 379 UnicodeString def("def"); 380 Formattable testArgs1[] = { abc, def }; 381 FieldPosition fieldpos(0); 382 assertEquals("format", 383 "There are abc files on def", 384 form->format(testArgs1, 2, buffer2, fieldpos, success)); 385 assertSuccess("format", success); 386 delete form; 387 } 388 389 void TestMessageFormat::testStaticFormat() 390 { 391 UErrorCode err = U_ZERO_ERROR; 392 Formattable arguments[] = { 393 (int32_t)7, 394 Formattable(UDate(8.71068e+011), Formattable::kIsDate), 395 "a disturbance in the Force" 396 }; 397 398 UnicodeString result; 399 result = MessageFormat::format( 400 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", 401 arguments, 402 3, 403 result, 404 err); 405 406 if (U_FAILURE(err)) { 407 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err)); 408 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err); 409 return; 410 } 411 412 const UnicodeString expected( 413 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", ""); 414 if (result != expected) { 415 errln("TestMessageFormat::testStaticFormat failed on test"); 416 logln( UnicodeString(" Result: ") + result ); 417 logln( UnicodeString(" Expected: ") + expected ); 418 } 419 } 420 421 /* When the default locale is tr, make sure that the pattern can still be parsed. */ 422 void TestMessageFormat::TestTurkishCasing() 423 { 424 UErrorCode err = U_ZERO_ERROR; 425 Locale saveDefaultLocale; 426 Locale::setDefault( Locale("tr"), err ); 427 428 Formattable arguments[] = { 429 (int32_t)7, 430 Formattable(UDate(8.71068e+011), Formattable::kIsDate), 431 "a disturbance in the Force" 432 }; 433 434 UnicodeString result; 435 result = MessageFormat::format( 436 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.", 437 arguments, 438 3, 439 result, 440 err); 441 442 if (U_FAILURE(err)) { 443 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err)); 444 return; 445 } 446 447 const UnicodeString expected( 448 "At 12:20:00 on 8 08 1997, there was a disturbance in the Force on planet 7.", ""); // Google patch 449 if (result != expected) { 450 errln("TestTurkishCasing failed on test"); 451 errln( UnicodeString(" Result: ") + result ); 452 errln( UnicodeString(" Expected: ") + expected ); 453 } 454 Locale::setDefault( saveDefaultLocale, err ); 455 } 456 457 void TestMessageFormat::testSimpleFormat(/* char* par */) 458 { 459 logln("running TestMessageFormat::testSimpleFormat"); 460 461 UErrorCode err = U_ZERO_ERROR; 462 463 Formattable testArgs1[] = {(int32_t)0, "MyDisk"}; 464 Formattable testArgs2[] = {(int32_t)1, "MyDisk"}; 465 Formattable testArgs3[] = {(int32_t)12, "MyDisk"}; 466 467 MessageFormat* form = new MessageFormat( 468 "The disk \"{1}\" contains {0} file(s).", err); 469 470 UnicodeString string; 471 FieldPosition ignore(FieldPosition::DONT_CARE); 472 form->format(testArgs1, 2, string, ignore, err); 473 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") { 474 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err)); 475 } 476 477 ignore.setField(FieldPosition::DONT_CARE); 478 string.remove(); 479 form->format(testArgs2, 2, string, ignore, err); 480 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") { 481 logln(string); 482 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string + " - " + u_errorName(err)); 483 } 484 485 ignore.setField(FieldPosition::DONT_CARE); 486 string.remove(); 487 form->format(testArgs3, 2, string, ignore, err); 488 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") { 489 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string + " - " + u_errorName(err)); 490 } 491 492 delete form; 493 } 494 495 void TestMessageFormat::testMsgFormatChoice(/* char* par */) 496 { 497 logln("running TestMessageFormat::testMsgFormatChoice"); 498 499 UErrorCode err = U_ZERO_ERROR; 500 501 MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err); 502 double filelimits[] = {0,1,2}; 503 UnicodeString filepart[] = {"no files","one file","{0,number} files"}; 504 ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3); 505 form->setFormat(1,*fileform); // NOT zero, see below 506 //is the format adopted? 507 508 FieldPosition ignore(FieldPosition::DONT_CARE); 509 UnicodeString string; 510 Formattable testArgs1[] = {(int32_t)0, "MyDisk"}; 511 form->format(testArgs1, 2, string, ignore, err); 512 if (string != "The disk \"MyDisk\" contains no files.") { 513 errln("TestMessageFormat::testMsgFormatChoice failed on test #1"); 514 } 515 516 ignore.setField(FieldPosition::DONT_CARE); 517 string.remove(); 518 Formattable testArgs2[] = {(int32_t)1, "MyDisk"}; 519 form->format(testArgs2, 2, string, ignore, err); 520 if (string != "The disk \"MyDisk\" contains one file.") { 521 errln("TestMessageFormat::testMsgFormatChoice failed on test #2"); 522 } 523 524 ignore.setField(FieldPosition::DONT_CARE); 525 string.remove(); 526 Formattable testArgs3[] = {(int32_t)1273, "MyDisk"}; 527 form->format(testArgs3, 2, string, ignore, err); 528 if (string != "The disk \"MyDisk\" contains 1,273 files.") { 529 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err)); 530 } 531 532 delete form; 533 delete fileform; 534 } 535 536 537 void TestMessageFormat::testMsgFormatPlural(/* char* par */) 538 { 539 logln("running TestMessageFormat::testMsgFormatPlural"); 540 541 UErrorCode err = U_ZERO_ERROR; 542 UnicodeString t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste."); 543 UnicodeString t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste."); 544 UnicodeString t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory."); 545 UnicodeString t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory."); 546 UnicodeString t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste."); 547 MessageFormat* mfNum = new MessageFormat(t1, Locale("fr"), err); 548 if (U_FAILURE(err)) { 549 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err)); 550 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err); 551 return; 552 } 553 Formattable testArgs1((int32_t)0); 554 FieldPosition ignore(FieldPosition::DONT_CARE); 555 UnicodeString numResult1; 556 mfNum->format(&testArgs1, 1, numResult1, ignore, err); 557 558 MessageFormat* mfAlpha = new MessageFormat(t2, Locale("fr"), err); 559 UnicodeString argName[] = {UnicodeString("argument")}; 560 UnicodeString argNameResult; 561 mfAlpha->format(argName, &testArgs1, 1, argNameResult, err); 562 if (U_FAILURE(err)) { 563 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err)); 564 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err); 565 delete mfNum; 566 return; 567 } 568 if ( numResult1 != argNameResult){ 569 errln("TestMessageFormat::testMsgFormatPlural #1"); 570 logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); 571 } 572 if ( numResult1 != UnicodeString("C\'est 0 fichier dans la liste.")) { 573 errln("TestMessageFormat::testMsgFormatPlural #1"); 574 logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); 575 } 576 err = U_ZERO_ERROR; 577 578 delete mfNum; 579 delete mfAlpha; 580 581 MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err); 582 numResult1.remove(); 583 Formattable testArgs2((int32_t)4); 584 mfNum2->format(&testArgs2, 1, numResult1, ignore, err); 585 MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err); 586 argNameResult.remove(); 587 mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err); 588 589 if (U_FAILURE(err)) { 590 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName"); 591 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err); 592 delete mfNum2; 593 return; 594 } 595 if ( numResult1 != argNameResult){ 596 errln("TestMessageFormat::testMsgFormatPlural #2"); 597 logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); 598 } 599 if ( numResult1 != UnicodeString("There are 4,0 zavoda in the directory.")) { 600 errln("TestMessageFormat::testMsgFormatPlural #2"); 601 logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); 602 } 603 604 delete mfNum2; 605 delete mfAlpha2; 606 607 // nested formats 608 err = U_ZERO_ERROR; 609 MessageFormat* msgFmt = new MessageFormat(t5, Locale("fr"), err); 610 if (U_FAILURE(err)) { 611 errln("TestMessageFormat::test nested PluralFormat with argumentName"); 612 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err); 613 delete msgFmt; 614 return; 615 } 616 Formattable testArgs3((int32_t)0); 617 argNameResult.remove(); 618 msgFmt->format(&testArgs3, 1, argNameResult, ignore, err); 619 if (U_FAILURE(err)) { 620 errln("TestMessageFormat::test nested PluralFormat with argumentName"); 621 } 622 if ( argNameResult!= UnicodeString("C'est 0,0 fichier dans la liste.")) { 623 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult); 624 logln(UnicodeString("The unexpected nested named PluralFormat.")); 625 } 626 delete msgFmt; 627 } 628 629 void TestMessageFormat::testApostropheInPluralAndSelect() { 630 UErrorCode errorCode = U_ZERO_ERROR; 631 MessageFormat msgFmt(UNICODE_STRING_SIMPLE( 632 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"), 633 Locale::getEnglish(), 634 errorCode); 635 if (U_FAILURE(errorCode)) { 636 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode)); 637 return; 638 } 639 UnicodeString expected = UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz"); 640 Formattable args[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") }; 641 internalFormat( 642 &msgFmt, args, 2, expected, 643 "MessageFormat with apostrophes in plural/select arguments failed:\n"); 644 } 645 646 void TestMessageFormat::internalFormat(MessageFormat* msgFmt , 647 Formattable* args , int32_t numOfArgs , 648 UnicodeString expected, const char* errMsg) 649 { 650 UnicodeString result; 651 FieldPosition ignore(FieldPosition::DONT_CARE); 652 UErrorCode status = U_ZERO_ERROR; 653 654 //Format with passed arguments 655 msgFmt->format( args , numOfArgs , result, ignore, status); 656 if (U_FAILURE(status)) { 657 dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) ); 658 } 659 //Compare expected with obtained result 660 if ( result!= expected ) { 661 UnicodeString err = UnicodeString(errMsg); 662 err+= UnicodeString(":Unexpected Result \n Expected: " + expected + "\n Obtained: " + result + "\n"); 663 dataerrln(err); 664 } 665 } 666 667 MessageFormat* TestMessageFormat::internalCreate( 668 UnicodeString pattern ,Locale locale ,UErrorCode &status , char* errMsg) 669 { 670 //Create the MessageFormat with simple SelectFormat 671 MessageFormat* msgFmt = new MessageFormat(pattern, locale, status); 672 if (U_FAILURE(status)) { 673 dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) ); 674 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status); 675 return NULL; 676 } 677 return msgFmt; 678 } 679 680 void TestMessageFormat::testMsgFormatSelect(/* char* par */) 681 { 682 logln("running TestMessageFormat::testMsgFormatSelect"); 683 684 UErrorCode err = U_ZERO_ERROR; 685 //French Pattern 686 UnicodeString t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."); 687 688 err = U_ZERO_ERROR; 689 //Create the MessageFormat with simple French pattern 690 MessageFormat* msgFmt1 = internalCreate(t1.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t1"); 691 if (!U_FAILURE(err)) { 692 //Arguments 693 Formattable testArgs10[] = {"Kirti","female"}; 694 Formattable testArgs11[] = {"Victor","other"}; 695 Formattable testArgs12[] = {"Ash","unknown"}; 696 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; 697 UnicodeString exp[] = { 698 "Kirti est all\\u00E9e \\u00E0 Paris." , 699 "Victor est all\\u00E9 \\u00E0 Paris.", 700 "Ash est all\\u00E9 \\u00E0 Paris."}; 701 //Format 702 for( int i=0; i< 3; i++){ 703 internalFormat( msgFmt1 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1"); 704 } 705 } 706 delete msgFmt1; 707 708 //Quoted French Pattern 709 UnicodeString t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris."); 710 err = U_ZERO_ERROR; 711 //Create the MessageFormat with Quoted French pattern 712 MessageFormat* msgFmt2 = internalCreate(t2.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t2"); 713 if (!U_FAILURE(err)) { 714 //Arguments 715 Formattable testArgs10[] = {"Kirti","female"}; 716 Formattable testArgs11[] = {"Victor","other"}; 717 Formattable testArgs12[] = {"Ash","male"}; 718 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; 719 UnicodeString exp[] = { 720 "Kirti est all\\u00E9e c'est \\u00E0 Paris." , 721 "Victor est all\\u00E9 c'est \\u00E0 Paris.", 722 "Ash est all\\u00E9 c'est \\u00E0 Paris."}; 723 //Format 724 for( int i=0; i< 3; i++){ 725 internalFormat( msgFmt2 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2"); 726 } 727 } 728 delete msgFmt2; 729 730 //English Pattern 731 UnicodeString t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books."); 732 err = U_ZERO_ERROR; 733 //Create the MessageFormat with English pattern 734 MessageFormat* msgFmt3 = internalCreate(t3, Locale("en"),err,(char*)"From TestMessageFormat::TestSelectFormat create t3"); 735 if (!U_FAILURE(err)) { 736 //Arguments 737 Formattable testArgs10[] = {"female"}; 738 Formattable testArgs11[] = {"other"}; 739 Formattable testArgs12[] = {"male"}; 740 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; 741 UnicodeString exp[] = { 742 "FEMALE FR company published new books." , 743 "FR otherValue published new books.", 744 "MALE FR company published new books."}; 745 //Format 746 for( int i=0; i< 3; i++){ 747 internalFormat( msgFmt3 , testArgs[i], 1, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t3"); 748 } 749 } 750 delete msgFmt3; 751 752 //Nested patterns with plural, number ,choice ,select format etc. 753 //Select Format with embedded number format 754 UnicodeString t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."); 755 err = U_ZERO_ERROR; 756 //Create the MessageFormat with Select Format with embedded number format (nested pattern) 757 MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4"); 758 if (!U_FAILURE(err)) { 759 //Arguments 760 Formattable testArgs10[] = {"Kirti","female",(int32_t)6}; 761 Formattable testArgs11[] = {"Kirti","female",100.100}; 762 Formattable testArgs12[] = {"Kirti","other",(int32_t)6}; 763 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; 764 UnicodeString exp[] = { 765 "Kirti est 6 all\\u00E9e \\u00E0 Paris." , 766 "Kirti est 100 all\\u00E9e \\u00E0 Paris.", 767 "Kirti est all\\u00E9 \\u00E0 Paris."}; 768 //Format 769 for( int i=0; i< 3; i++){ 770 internalFormat( msgFmt4 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4"); 771 } 772 } 773 delete msgFmt4; 774 775 //Plural format with embedded select format 776 UnicodeString t5("{0} {1, plural, one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}} other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}} \\u00E0 Paris."); 777 err = U_ZERO_ERROR; 778 //Create the MessageFormat with Plural format with embedded select format(nested pattern) 779 MessageFormat* msgFmt5 = internalCreate(t5.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t5"); 780 if (!U_FAILURE(err)) { 781 //Arguments 782 Formattable testArgs10[] = {"Kirti",(int32_t)6,"female"}; 783 Formattable testArgs11[] = {"Kirti",(int32_t)1,"female"}; 784 Formattable testArgs12[] = {"Ash",(int32_t)1,"other"}; 785 Formattable testArgs13[] = {"Ash",(int32_t)5,"other"}; 786 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13}; 787 UnicodeString exp[] = { 788 "Kirti sont all\\u00E9es \\u00E0 Paris." , 789 "Kirti est all\\u00E9e \\u00E0 Paris.", 790 "Ash est all\\u00E9 \\u00E0 Paris.", 791 "Ash sont all\\u00E9s \\u00E0 Paris."}; 792 //Format 793 for( int i=0; i< 4; i++){ 794 internalFormat( msgFmt5 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5"); 795 } 796 } 797 delete msgFmt5; 798 799 err = U_ZERO_ERROR; 800 //Select, plural, and number formats heavily nested 801 UnicodeString t6("{0} und {1, select, female {{2, plural, one {{3, select, female {ihre Freundin} other {ihr Freund}} } other {ihre {2, number, integer} {3, select, female {Freundinnen} other {Freunde}} } }} other{{2, plural, one {{3, select, female {seine Freundin} other {sein Freund}}} other {seine {2, number, integer} {3, select, female {Freundinnen} other {Freunde}}}}} } gingen nach Paris."); 802 //Create the MessageFormat with Select, plural, and number formats heavily nested 803 MessageFormat* msgFmt6 = internalCreate(t6, Locale("de"),err,(char*)"From TestMessageFormat::TestSelectFormat create t6"); 804 if (!U_FAILURE(err)) { 805 //Arguments 806 Formattable testArgs10[] = {"Kirti","other",(int32_t)1,"other"}; 807 Formattable testArgs11[] = {"Kirti","other",(int32_t)6,"other"}; 808 Formattable testArgs12[] = {"Kirti","other",(int32_t)1,"female"}; 809 Formattable testArgs13[] = {"Kirti","other",(int32_t)3,"female"}; 810 Formattable testArgs14[] = {"Kirti","female",(int32_t)1,"female"}; 811 Formattable testArgs15[] = {"Kirti","female",(int32_t)5,"female"}; 812 Formattable testArgs16[] = {"Kirti","female",(int32_t)1,"other"}; 813 Formattable testArgs17[] = {"Kirti","female",(int32_t)5,"other"}; 814 Formattable testArgs18[] = {"Kirti","mixed",(int32_t)1,"mixed"}; 815 Formattable testArgs19[] = {"Kirti","mixed",(int32_t)1,"other"}; 816 Formattable testArgs20[] = {"Kirti","female",(int32_t)1,"mixed"}; 817 Formattable testArgs21[] = {"Kirti","mixed",(int32_t)5,"mixed"}; 818 Formattable testArgs22[] = {"Kirti","mixed",(int32_t)5,"other"}; 819 Formattable testArgs23[] = {"Kirti","female",(int32_t)5,"mixed"}; 820 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13, 821 testArgs14,testArgs15,testArgs16,testArgs17, 822 testArgs18,testArgs19,testArgs20,testArgs21, 823 testArgs22,testArgs23 }; 824 UnicodeString exp[] = { 825 "Kirti und sein Freund gingen nach Paris." , 826 "Kirti und seine 6 Freunde gingen nach Paris." , 827 "Kirti und seine Freundin gingen nach Paris.", 828 "Kirti und seine 3 Freundinnen gingen nach Paris.", 829 "Kirti und ihre Freundin gingen nach Paris.", 830 "Kirti und ihre 5 Freundinnen gingen nach Paris.", 831 "Kirti und ihr Freund gingen nach Paris.", 832 "Kirti und ihre 5 Freunde gingen nach Paris.", 833 "Kirti und sein Freund gingen nach Paris.", 834 "Kirti und sein Freund gingen nach Paris.", 835 "Kirti und ihr Freund gingen nach Paris.", 836 "Kirti und seine 5 Freunde gingen nach Paris." , 837 "Kirti und seine 5 Freunde gingen nach Paris." , 838 "Kirti und ihre 5 Freunde gingen nach Paris." 839 }; 840 //Format 841 for( int i=0; i< 14; i++){ 842 internalFormat( msgFmt6 , testArgs[i], 4, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t6"); 843 } 844 } 845 delete msgFmt6; 846 } 847 848 //--------------------------------- 849 // API Tests 850 //--------------------------------- 851 852 void TestMessageFormat::testCopyConstructor() 853 { 854 UErrorCode success = U_ZERO_ERROR; 855 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); 856 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); 857 MessageFormat *y = 0; 858 y = new MessageFormat(*x); 859 if ( (*x == *y) && 860 (*x != *z) && 861 (*y != *z) ) 862 logln("First test (operator ==): Passed!"); 863 else { 864 errln("TestMessageFormat::testCopyConstructor failed #1"); 865 logln("First test (operator ==): Failed!"); 866 } 867 if ( ((*x == *y) && (*y == *x)) && 868 ((*x != *z) && (*z != *x)) && 869 ((*y != *z) && (*z != *y)) ) 870 logln("Second test (equals): Passed!"); 871 else { 872 errln("TestMessageFormat::testCopyConstructor failed #2"); 873 logln("Second test (equals): Failed!"); 874 } 875 876 delete x; 877 delete y; 878 delete z; 879 } 880 881 882 void TestMessageFormat::testAssignment() 883 { 884 UErrorCode success = U_ZERO_ERROR; 885 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); 886 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); 887 MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success); 888 *y = *x; 889 if ( (*x == *y) && 890 (*x != *z) && 891 (*y != *z) ) 892 logln("First test (operator ==): Passed!"); 893 else { 894 errln( "TestMessageFormat::testAssignment failed #1"); 895 logln("First test (operator ==): Failed!"); 896 } 897 if ( ((*x == *y) && (*y == *x)) && 898 ((*x != *z) && (*z != *x)) && 899 ((*y != *z) && (*z != *y)) ) 900 logln("Second test (equals): Passed!"); 901 else { 902 errln("TestMessageFormat::testAssignment failed #2"); 903 logln("Second test (equals): Failed!"); 904 } 905 906 delete x; 907 delete y; 908 delete z; 909 } 910 911 void TestMessageFormat::testClone() 912 { 913 UErrorCode success = U_ZERO_ERROR; 914 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); 915 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); 916 MessageFormat *y = 0; 917 y = (MessageFormat*)x->clone(); 918 if ( (*x == *y) && 919 (*x != *z) && 920 (*y != *z) ) 921 logln("First test (operator ==): Passed!"); 922 else { 923 errln("TestMessageFormat::testClone failed #1"); 924 logln("First test (operator ==): Failed!"); 925 } 926 if ( ((*x == *y) && (*y == *x)) && 927 ((*x != *z) && (*z != *x)) && 928 ((*y != *z) && (*z != *y)) ) 929 logln("Second test (equals): Passed!"); 930 else { 931 errln("TestMessageFormat::testClone failed #2"); 932 logln("Second test (equals): Failed!"); 933 } 934 935 delete x; 936 delete y; 937 delete z; 938 } 939 940 void TestMessageFormat::testEquals() 941 { 942 UErrorCode success = U_ZERO_ERROR; 943 MessageFormat x("There are {0} files on {1}", success); 944 MessageFormat y("There are {0} files on {1}", success); 945 if (!(x == y)) { 946 errln( "TestMessageFormat::testEquals failed #1"); 947 logln("First test (operator ==): Failed!"); 948 } 949 950 } 951 952 void TestMessageFormat::testNotEquals() 953 { 954 UErrorCode success = U_ZERO_ERROR; 955 MessageFormat x("There are {0} files on {1}", success); 956 MessageFormat y(x); 957 y.setLocale(Locale("fr")); 958 if (!(x != y)) { 959 errln( "TestMessageFormat::testEquals failed #1"); 960 logln("First test (operator !=): Failed!"); 961 } 962 y = x; 963 y.applyPattern("There are {0} files on {1} the disk", success); 964 if (!(x != y)) { 965 errln( "TestMessageFormat::testEquals failed #1"); 966 logln("Second test (operator !=): Failed!"); 967 } 968 } 969 970 971 void TestMessageFormat::testSetLocale() 972 { 973 UErrorCode err = U_ZERO_ERROR; 974 GregorianCalendar cal(err); 975 Formattable arguments[] = { 976 456.83, 977 Formattable(UDate(8.71068e+011), Formattable::kIsDate), 978 "deposit" 979 }; 980 981 UnicodeString result; 982 983 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; 984 UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; 985 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH 986 // Just use unlocalized currency symbol. 987 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; 988 UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of "; 989 compareStrEng += (UChar) 0x00a4; 990 compareStrEng += "456.83."; 991 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN 992 // Just use unlocalized currency symbol. 993 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM."; 994 UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of "; 995 compareStrGer += "456,83"; 996 compareStrGer += (UChar) 0x00a0; 997 compareStrGer += (UChar) 0x00a4; 998 compareStrGer += "."; 999 1000 MessageFormat msg( formatStr, err); 1001 result = ""; 1002 FieldPosition pos(0); 1003 result = msg.format( 1004 arguments, 1005 3, 1006 result, 1007 pos, 1008 err); 1009 1010 logln(result); 1011 if (result != compareStrEng) { 1012 dataerrln("*** MSG format err. - %s", u_errorName(err)); 1013 } 1014 1015 msg.setLocale(Locale::getEnglish()); 1016 UBool getLocale_ok = TRUE; 1017 if (msg.getLocale() != Locale::getEnglish()) { 1018 errln("*** MSG getLocal err."); 1019 getLocale_ok = FALSE; 1020 } 1021 1022 msg.setLocale(Locale::getGerman()); 1023 1024 if (msg.getLocale() != Locale::getGerman()) { 1025 errln("*** MSG getLocal err."); 1026 getLocale_ok = FALSE; 1027 } 1028 1029 msg.applyPattern( formatStr, err); 1030 1031 pos.setField(0); 1032 result = ""; 1033 result = msg.format( 1034 arguments, 1035 3, 1036 result, 1037 pos, 1038 err); 1039 1040 logln(result); 1041 if (result == compareStrGer) { 1042 logln("MSG setLocale tested."); 1043 }else{ 1044 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err)); 1045 } 1046 1047 if (getLocale_ok) { 1048 logln("MSG getLocale tested."); 1049 } 1050 } 1051 1052 void TestMessageFormat::testFormat() 1053 { 1054 UErrorCode err = U_ZERO_ERROR; 1055 GregorianCalendar cal(err); 1056 1057 const Formattable ftarray[] = 1058 { 1059 Formattable( UDate(8.71068e+011), Formattable::kIsDate ) 1060 }; 1061 const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable); 1062 Formattable ft_arr( ftarray, ft_cnt ); 1063 1064 Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate); 1065 1066 UnicodeString result; 1067 1068 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; 1069 UnicodeString formatStr = "On {0,date}, it began."; 1070 UnicodeString compareStr = "On Aug 8, 1997, it began."; 1071 1072 err = U_ZERO_ERROR; 1073 MessageFormat msg( formatStr, err); 1074 FieldPosition fp(0); 1075 1076 result = ""; 1077 fp = 0; 1078 result = msg.format( 1079 *fmt, 1080 result, 1081 //FieldPosition(0), 1082 fp, 1083 err); 1084 1085 if (err != U_ILLEGAL_ARGUMENT_ERROR) { 1086 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err)); 1087 } 1088 err = U_ZERO_ERROR; 1089 1090 result = ""; 1091 fp = 0; 1092 result = msg.format( 1093 ft_arr, 1094 result, 1095 //FieldPosition(0), 1096 fp, 1097 err); 1098 1099 logln("MSG format( Formattable&, ... ) expected:" + compareStr); 1100 logln("MSG format( Formattable&, ... ) result:" + result); 1101 if (result != compareStr) { 1102 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err)); 1103 }else{ 1104 logln("MSG format( Formattable&, ... ) tested."); 1105 } 1106 1107 delete fmt; 1108 1109 } 1110 1111 void TestMessageFormat::testParse() 1112 { 1113 UErrorCode err = U_ZERO_ERROR; 1114 int32_t count; 1115 UnicodeString msgFormatString = "{0} =sep= {1}"; 1116 MessageFormat msg( msgFormatString, err); 1117 UnicodeString source = "abc =sep= def"; 1118 UnicodeString tmp1, tmp2; 1119 1120 Formattable* fmt_arr = msg.parse( source, count, err ); 1121 if (U_FAILURE(err) || (!fmt_arr)) { 1122 errln("*** MSG parse (ustring, count, err) error."); 1123 }else{ 1124 logln("MSG parse -- count: %d", count); 1125 if (count != 2) { 1126 errln("*** MSG parse (ustring, count, err) count err."); 1127 }else{ 1128 if ((fmt_arr[0].getType() == Formattable::kString) 1129 && (fmt_arr[1].getType() == Formattable::kString) 1130 && (fmt_arr[0].getString(tmp1) == "abc") 1131 && (fmt_arr[1].getString(tmp2) == "def")) { 1132 logln("MSG parse (ustring, count, err) tested."); 1133 }else{ 1134 errln("*** MSG parse (ustring, count, err) result err."); 1135 } 1136 } 1137 } 1138 delete[] fmt_arr; 1139 1140 ParsePosition pp(0); 1141 1142 fmt_arr = msg.parse( source, pp, count ); 1143 if ((pp == 0) || (!fmt_arr)) { 1144 errln("*** MSG parse (ustring, parsepos., count) error."); 1145 }else{ 1146 logln("MSG parse -- count: %d", count); 1147 if (count != 2) { 1148 errln("*** MSG parse (ustring, parsepos., count) count err."); 1149 }else{ 1150 if ((fmt_arr[0].getType() == Formattable::kString) 1151 && (fmt_arr[1].getType() == Formattable::kString) 1152 && (fmt_arr[0].getString(tmp1) == "abc") 1153 && (fmt_arr[1].getString(tmp2) == "def")) { 1154 logln("MSG parse (ustring, parsepos., count) tested."); 1155 }else{ 1156 errln("*** MSG parse (ustring, parsepos., count) result err."); 1157 } 1158 } 1159 } 1160 delete[] fmt_arr; 1161 1162 pp = 0; 1163 Formattable fmta; 1164 1165 msg.parseObject( source, fmta, pp ); 1166 if (pp == 0) { 1167 errln("*** MSG parse (ustring, Formattable, parsepos ) error."); 1168 }else{ 1169 logln("MSG parse -- count: %d", count); 1170 fmta.getArray(count); 1171 if (count != 2) { 1172 errln("*** MSG parse (ustring, Formattable, parsepos ) count err."); 1173 }else{ 1174 if ((fmta[0].getType() == Formattable::kString) 1175 && (fmta[1].getType() == Formattable::kString) 1176 && (fmta[0].getString(tmp1) == "abc") 1177 && (fmta[1].getString(tmp2) == "def")) { 1178 logln("MSG parse (ustring, Formattable, parsepos ) tested."); 1179 }else{ 1180 errln("*** MSG parse (ustring, Formattable, parsepos ) result err."); 1181 } 1182 } 1183 } 1184 } 1185 1186 1187 void TestMessageFormat::testAdopt() 1188 { 1189 UErrorCode err = U_ZERO_ERROR; 1190 1191 UnicodeString formatStr("{0,date},{1},{2,number}", ""); 1192 UnicodeString formatStrChange("{0,number},{1,number},{2,date}", ""); 1193 err = U_ZERO_ERROR; 1194 MessageFormat msg( formatStr, err); 1195 MessageFormat msgCmp( formatStr, err); 1196 if (U_FAILURE(err)) { 1197 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err)); 1198 return; 1199 } 1200 int32_t count, countCmp; 1201 const Format** formats = msg.getFormats(count); 1202 const Format** formatsCmp = msgCmp.getFormats(countCmp); 1203 const Format** formatsChg = 0; 1204 const Format** formatsAct = 0; 1205 int32_t countAct; 1206 const Format* a; 1207 const Format* b; 1208 UnicodeString patCmp; 1209 UnicodeString patAct; 1210 Format** formatsToAdopt; 1211 1212 if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) { 1213 dataerrln("Error getting Formats"); 1214 return; 1215 } 1216 1217 int32_t i; 1218 1219 for (i = 0; i < count; i++) { 1220 a = formats[i]; 1221 b = formatsCmp[i]; 1222 if ((a != NULL) && (b != NULL)) { 1223 if (*a != *b) { 1224 errln("a != b"); 1225 return; 1226 } 1227 }else if ((a != NULL) || (b != NULL)) { 1228 errln("(a != NULL) || (b != NULL)"); 1229 return; 1230 } 1231 } 1232 1233 msg.applyPattern( formatStrChange, err ); //set msg formats to something different 1234 int32_t countChg; 1235 formatsChg = msg.getFormats(countChg); // tested function 1236 if (!formatsChg || (countChg != count)) { 1237 errln("Error getting Formats"); 1238 return; 1239 } 1240 1241 UBool diff; 1242 diff = TRUE; 1243 for (i = 0; i < count; i++) { 1244 a = formatsChg[i]; 1245 b = formatsCmp[i]; 1246 if ((a != NULL) && (b != NULL)) { 1247 if (*a == *b) { 1248 logln("formatsChg == formatsCmp at index %d", i); 1249 diff = FALSE; 1250 } 1251 } 1252 } 1253 if (!diff) { 1254 errln("*** MSG getFormats diff err."); 1255 return; 1256 } 1257 1258 logln("MSG getFormats tested."); 1259 1260 msg.setFormats( formatsCmp, countCmp ); //tested function 1261 1262 formatsAct = msg.getFormats(countAct); 1263 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { 1264 errln("Error getting Formats"); 1265 return; 1266 } 1267 1268 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); 1269 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 1270 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); 1271 msg.toPattern(patCmp.remove()); 1272 if (!patCmp.isBogus()) { 1273 errln("msg.setFormat().toPattern() succeeds."); 1274 } 1275 1276 for (i = 0; i < countAct; i++) { 1277 a = formatsAct[i]; 1278 b = formatsCmp[i]; 1279 if ((a != NULL) && (b != NULL)) { 1280 if (*a != *b) { 1281 logln("formatsAct != formatsCmp at index %d", i); 1282 errln("a != b"); 1283 return; 1284 } 1285 }else if ((a != NULL) || (b != NULL)) { 1286 errln("(a != NULL) || (b != NULL)"); 1287 return; 1288 } 1289 } 1290 logln("MSG setFormats tested."); 1291 1292 //---- 1293 1294 msg.applyPattern( formatStrChange, err ); //set msg formats to something different 1295 1296 formatsToAdopt = new Format* [countCmp]; 1297 if (!formatsToAdopt) { 1298 errln("memory allocation error"); 1299 return; 1300 } 1301 1302 for (i = 0; i < countCmp; i++) { 1303 if (formatsCmp[i] == NULL) { 1304 formatsToAdopt[i] = NULL; 1305 }else{ 1306 formatsToAdopt[i] = formatsCmp[i]->clone(); 1307 if (!formatsToAdopt[i]) { 1308 errln("Can't clone format at index %d", i); 1309 return; 1310 } 1311 } 1312 } 1313 msg.adoptFormats( formatsToAdopt, countCmp ); // function to test 1314 delete[] formatsToAdopt; 1315 1316 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); 1317 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 1318 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); 1319 1320 formatsAct = msg.getFormats(countAct); 1321 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { 1322 errln("Error getting Formats"); 1323 return; 1324 } 1325 1326 for (i = 0; i < countAct; i++) { 1327 a = formatsAct[i]; 1328 b = formatsCmp[i]; 1329 if ((a != NULL) && (b != NULL)) { 1330 if (*a != *b) { 1331 errln("a != b"); 1332 return; 1333 } 1334 }else if ((a != NULL) || (b != NULL)) { 1335 errln("(a != NULL) || (b != NULL)"); 1336 return; 1337 } 1338 } 1339 logln("MSG adoptFormats tested."); 1340 1341 //---- adoptFormat 1342 1343 msg.applyPattern( formatStrChange, err ); //set msg formats to something different 1344 1345 formatsToAdopt = new Format* [countCmp]; 1346 if (!formatsToAdopt) { 1347 errln("memory allocation error"); 1348 return; 1349 } 1350 1351 for (i = 0; i < countCmp; i++) { 1352 if (formatsCmp[i] == NULL) { 1353 formatsToAdopt[i] = NULL; 1354 }else{ 1355 formatsToAdopt[i] = formatsCmp[i]->clone(); 1356 if (!formatsToAdopt[i]) { 1357 errln("Can't clone format at index %d", i); 1358 return; 1359 } 1360 } 1361 } 1362 1363 for ( i = 0; i < countCmp; i++ ) { 1364 msg.adoptFormat( i, formatsToAdopt[i] ); // function to test 1365 } 1366 delete[] formatsToAdopt; // array itself not needed in this case; 1367 1368 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); 1369 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 1370 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); 1371 1372 formatsAct = msg.getFormats(countAct); 1373 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { 1374 errln("Error getting Formats"); 1375 return; 1376 } 1377 1378 for (i = 0; i < countAct; i++) { 1379 a = formatsAct[i]; 1380 b = formatsCmp[i]; 1381 if ((a != NULL) && (b != NULL)) { 1382 if (*a != *b) { 1383 errln("a != b"); 1384 return; 1385 } 1386 }else if ((a != NULL) || (b != NULL)) { 1387 errln("(a != NULL) || (b != NULL)"); 1388 return; 1389 } 1390 } 1391 logln("MSG adoptFormat tested."); 1392 } 1393 1394 // This test is a regression test for a fixed bug in the copy constructor. 1395 // It is kept as a global function rather than as a method since the test depends on memory values. 1396 // (At least before the bug was fixed, whether it showed up or not depended on memory contents, 1397 // which is probably why it didn't show up in the regular test for the copy constructor.) 1398 // For this reason, the test isn't changed even though it contains function calls whose results are 1399 // not tested and had no problems. Actually, the test failed by *crashing*. 1400 static void _testCopyConstructor2() 1401 { 1402 UErrorCode status = U_ZERO_ERROR; 1403 UnicodeString formatStr("Hello World on {0,date,full}", ""); 1404 UnicodeString resultStr(" ", ""); 1405 UnicodeString result; 1406 FieldPosition fp(0); 1407 UDate d = Calendar::getNow(); 1408 const Formattable fargs( d, Formattable::kIsDate ); 1409 1410 MessageFormat* fmt1 = new MessageFormat( formatStr, status ); 1411 MessageFormat* fmt2 = NULL; 1412 MessageFormat* fmt3 = NULL; 1413 MessageFormat* fmt4 = NULL; 1414 1415 if (fmt1 == NULL) { 1416 it_err("testCopyConstructor2: (fmt1 != NULL)"); 1417 goto cleanup; 1418 } 1419 1420 fmt2 = new MessageFormat( *fmt1 ); 1421 result = fmt1->format( &fargs, 1, resultStr, fp, status ); 1422 1423 if (fmt2 == NULL) { 1424 it_err("testCopyConstructor2: (fmt2 != NULL)"); 1425 goto cleanup; 1426 } 1427 1428 fmt3 = (MessageFormat*) fmt1->clone(); 1429 fmt4 = (MessageFormat*) fmt2->clone(); 1430 1431 if (fmt3 == NULL) { 1432 it_err("testCopyConstructor2: (fmt3 != NULL)"); 1433 goto cleanup; 1434 } 1435 if (fmt4 == NULL) { 1436 it_err("testCopyConstructor2: (fmt4 != NULL)"); 1437 goto cleanup; 1438 } 1439 1440 result = fmt1->format( &fargs, 1, resultStr, fp, status ); 1441 result = fmt2->format( &fargs, 1, resultStr, fp, status ); 1442 result = fmt3->format( &fargs, 1, resultStr, fp, status ); 1443 result = fmt4->format( &fargs, 1, resultStr, fp, status ); 1444 1445 cleanup: 1446 delete fmt1; 1447 delete fmt2; 1448 delete fmt3; 1449 delete fmt4; 1450 } 1451 1452 void TestMessageFormat::testCopyConstructor2() { 1453 _testCopyConstructor2(); 1454 } 1455 1456 /** 1457 * Verify that MessageFormat accomodates more than 10 arguments and 1458 * more than 10 subformats. 1459 */ 1460 void TestMessageFormat::TestUnlimitedArgsAndSubformats() { 1461 UErrorCode ec = U_ZERO_ERROR; 1462 const UnicodeString pattern = 1463 "On {0,date} (aka {0,date,short}, aka {0,date,long}) " 1464 "at {0,time} (aka {0,time,short}, aka {0,time,long}) " 1465 "there were {1,number} werjes " 1466 "(a {3,number,percent} increase over {2,number}) " 1467 "despite the {4}''s efforts " 1468 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}."; 1469 MessageFormat msg(pattern, ec); 1470 if (U_FAILURE(ec)) { 1471 dataerrln("FAIL: constructor failed - %s", u_errorName(ec)); 1472 return; 1473 } 1474 1475 const Formattable ARGS[] = { 1476 Formattable(UDate(1e13), Formattable::kIsDate), 1477 Formattable((int32_t)1303), 1478 Formattable((int32_t)1202), 1479 Formattable(1303.0/1202 - 1), 1480 Formattable("Glimmung"), 1481 Formattable("the printers"), 1482 Formattable("Nick"), 1483 Formattable("his father"), 1484 Formattable("his mother"), 1485 Formattable("the spiddles"), 1486 Formattable("of course"), 1487 Formattable("Horace"), 1488 }; 1489 const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]); 1490 Formattable ARGS_OBJ(ARGS, ARGS_LENGTH); 1491 1492 UnicodeString expected = 1493 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) " 1494 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) " 1495 "there were 1,303 werjes " 1496 "(a 8% increase over 1,202) " 1497 "despite the Glimmung's efforts " 1498 "and to delight of the printers, Nick, his father, " 1499 "his mother, the spiddles, and of course Horace."; 1500 UnicodeString result; 1501 msg.format(ARGS_OBJ, result, ec); 1502 if (result == expected) { 1503 logln(result); 1504 } else { 1505 errln((UnicodeString)"FAIL: Got " + result + 1506 ", expected " + expected); 1507 } 1508 } 1509 1510 // test RBNF extensions to message format 1511 void TestMessageFormat::TestRBNF(void) { 1512 // WARNING: this depends on the RBNF formats for en_US 1513 Locale locale("en", "US", ""); 1514 1515 UErrorCode ec = U_ZERO_ERROR; 1516 1517 UnicodeString values[] = { 1518 // decimal values do not format completely for ordinal or duration, and 1519 // do not always parse, so do not include them 1520 "0", "1", "12", "100", "123", "1001", "123,456", "-17", 1521 }; 1522 int32_t values_count = sizeof(values)/sizeof(values[0]); 1523 1524 UnicodeString formats[] = { 1525 "There are {0,spellout} files to search.", 1526 "There are {0,spellout,%simplified} files to search.", 1527 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.", 1528 "This is the {0,ordinal} file to search.", 1529 "Searching this file will take {0,duration} to complete.", 1530 "Searching this file will take {0,duration,%with-words} to complete.", 1531 }; 1532 int32_t formats_count = sizeof(formats)/sizeof(formats[0]); 1533 1534 Formattable args[1]; 1535 1536 NumberFormat* numFmt = NumberFormat::createInstance(locale, ec); 1537 if (U_FAILURE(ec)) { 1538 dataerrln("Error calling NumberFormat::createInstance()"); 1539 return; 1540 } 1541 1542 for (int i = 0; i < formats_count; ++i) { 1543 MessageFormat* fmt = new MessageFormat(formats[i], locale, ec); 1544 logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'"); 1545 1546 for (int j = 0; j < values_count; ++j) { 1547 ec = U_ZERO_ERROR; 1548 numFmt->parse(values[j], args[0], ec); 1549 if (U_FAILURE(ec)) { 1550 errln((UnicodeString)"Failed to parse test argument " + values[j]); 1551 } else { 1552 FieldPosition fp(0); 1553 UnicodeString result; 1554 fmt->format(args, 1, result, fp, ec); 1555 logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec)); 1556 1557 int32_t count = 0; 1558 Formattable* parseResult = fmt->parse(result, count, ec); 1559 if (count != 1) { 1560 errln((UnicodeString)"parse returned " + count + " args"); 1561 } else if (parseResult[0] != args[0]) { 1562 errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0])); 1563 } 1564 delete []parseResult; 1565 } 1566 } 1567 delete fmt; 1568 } 1569 delete numFmt; 1570 } 1571 1572 UnicodeString TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern& pattern) { 1573 UnicodeString us(pattern.getPatternString()); 1574 int count = pattern.countParts(); 1575 for (int i = count; i > 0;) { 1576 const MessagePattern::Part& part = pattern.getPart(--i); 1577 if (part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) { 1578 us.remove(part.getIndex(), part.getLimit() - part.getIndex()); 1579 } 1580 } 1581 return us; 1582 } 1583 1584 void TestMessageFormat::TestApostropheMode() { 1585 UErrorCode status = U_ZERO_ERROR; 1586 MessagePattern *ado_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL, status); 1587 MessagePattern *adr_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED, status); 1588 if (ado_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) { 1589 errln("wrong value from ado_mp->getApostropheMode()."); 1590 } 1591 if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) { 1592 errln("wrong value from adr_mp->getApostropheMode()."); 1593 } 1594 1595 1596 UnicodeString tuples[] = { 1597 // Desired output 1598 // DOUBLE_OPTIONAL pattern 1599 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL) 1600 "I see {many}", "I see '{many}'", "", 1601 "I said {'Wow!'}", "I said '{''Wow!''}'", "", 1602 "I dont know", "I dont know", "I don't know", 1603 "I don't know", "I don't know", "I don''t know", 1604 "I don't know", "I don''t know", "I don''t know" 1605 }; 1606 int32_t tuples_count = UPRV_LENGTHOF(tuples); 1607 1608 for (int i = 0; i < tuples_count; i += 3) { 1609 UnicodeString& desired = tuples[i]; 1610 UnicodeString& ado_pattern = tuples[i + 1]; 1611 UErrorCode status = U_ZERO_ERROR; 1612 assertEquals("DOUBLE_OPTIONAL failure", 1613 desired, 1614 GetPatternAndSkipSyntax(ado_mp->parse(ado_pattern, NULL, status))); 1615 UnicodeString& adr_pattern = tuples[i + 2].isEmpty() ? ado_pattern : tuples[i + 2]; 1616 assertEquals("DOUBLE_REQUIRED failure", desired, 1617 GetPatternAndSkipSyntax(adr_mp->parse(adr_pattern, NULL, status))); 1618 } 1619 delete adr_mp; 1620 delete ado_mp; 1621 } 1622 1623 1624 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode. 1625 void TestMessageFormat::TestCompatibleApostrophe() { 1626 // Message with choice argument which does not contain another argument. 1627 // The JDK performs only one apostrophe-quoting pass on this pattern. 1628 UnicodeString pattern = "ab{0,choice,0#1'2''3'''4''''.}yz"; 1629 1630 UErrorCode ec = U_ZERO_ERROR; 1631 MessageFormat compMsg("", Locale::getUS(), ec); 1632 compMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, ec); 1633 if (compMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) { 1634 errln("wrong value from compMsg.getApostropheMode()."); 1635 } 1636 1637 MessageFormat icuMsg("", Locale::getUS(), ec); 1638 icuMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_OPTIONAL, NULL, ec); 1639 if (icuMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) { 1640 errln("wrong value from icuMsg.getApostropheMode()."); 1641 } 1642 1643 Formattable zero0[] = { (int32_t)0 }; 1644 FieldPosition fieldpos(0); 1645 UnicodeString buffer1, buffer2; 1646 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", 1647 "ab12'3'4''.yz", 1648 compMsg.format(zero0, 1, buffer1, fieldpos, ec)); 1649 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", 1650 "ab1'2'3''4''.yz", 1651 icuMsg.format(zero0, 1, buffer2, fieldpos, ec)); 1652 1653 // Message with choice argument which contains a nested simple argument. 1654 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes. 1655 buffer1.remove(); 1656 buffer2.remove(); 1657 pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz"; 1658 compMsg.applyPattern(pattern, ec); 1659 icuMsg.applyPattern(pattern, ec); 1660 if (U_FAILURE(ec)) { 1661 dataerrln("Unable to applyPattern - %s", u_errorName(ec)); 1662 } else { 1663 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", 1664 "ab1234'.0xyz", 1665 compMsg.format(zero0, 1, buffer1, fieldpos, ec)); 1666 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", 1667 "ab1'2'3''4''.#x0yz", 1668 icuMsg.format(zero0, 1, buffer2, fieldpos, ec)); 1669 } 1670 1671 // This part is copied over from Java tests but cannot be properly tested here 1672 // because we do not have a live reference implementation with JDK behavior. 1673 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass. 1674 /* 1675 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''."); 1676 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", 1677 "12'3'4''.", 1678 choice.format(0)); 1679 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}"); 1680 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", 1681 "12'3'4''.{0,number,#x}", 1682 choice.format(0)); 1683 */ 1684 } 1685 1686 void TestMessageFormat::testAutoQuoteApostrophe(void) { 1687 const char* patterns[] = { // pattern, expected pattern 1688 "'", "''", 1689 "''", "''", 1690 "'{", "'{'", 1691 "' {", "'' {", 1692 "'a", "''a", 1693 "'{'a", "'{'a", 1694 "'{a'", "'{a'", 1695 "'{}", "'{}'", 1696 "{'", "{'", 1697 "{'a", "{'a", 1698 "{'a{}'a}'a", "{'a{}'a}''a", 1699 "'}'", "'}'", 1700 "'} '{'}'", "'} '{'}''", 1701 "'} {{{''", "'} {{{'''", 1702 }; 1703 int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]); 1704 1705 for (int i = 0; i < pattern_count; i += 2) { 1706 UErrorCode status = U_ZERO_ERROR; 1707 UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status); 1708 UnicodeString target(patterns[i+1]); 1709 if (target != result) { 1710 const int BUF2_LEN = 64; 1711 char buf[256]; 1712 char buf2[BUF2_LEN]; 1713 int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN); 1714 if (len >= BUF2_LEN) { 1715 buf2[BUF2_LEN-1] = 0; 1716 } 1717 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2); 1718 errln(buf); 1719 } 1720 } 1721 } 1722 1723 void TestMessageFormat::testCoverage(void) { 1724 UErrorCode status = U_ZERO_ERROR; 1725 UnicodeString testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste."); 1726 MessageFormat *msgfmt = new MessageFormat(testformat, Locale("fr"), status); 1727 if (msgfmt == NULL || U_FAILURE(status)) { 1728 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status)); 1729 return; 1730 } 1731 if (!msgfmt->usesNamedArguments()) { 1732 errln("FAIL: Unable to detect usage of named arguments."); 1733 } 1734 const double limit[] = {0.0, 1.0, 2.0}; 1735 const UnicodeString formats[] = {"0.0<=Arg<1.0", 1736 "1.0<=Arg<2.0", 1737 "2.0<-Arg"}; 1738 ChoiceFormat cf(limit, formats, 3); 1739 1740 msgfmt->setFormat("set", cf, status); 1741 1742 StringEnumeration *en = msgfmt->getFormatNames(status); 1743 if (en == NULL || U_FAILURE(status)) { 1744 errln("FAIL: Unable to get format names enumeration."); 1745 } else { 1746 int32_t count = 0; 1747 en->reset(status); 1748 count = en->count(status); 1749 if (U_FAILURE(status)) { 1750 errln("FAIL: Unable to get format name enumeration count."); 1751 } else { 1752 for (int32_t i = 0; i < count; i++) { 1753 en->snext(status); 1754 if (U_FAILURE(status)) { 1755 errln("FAIL: Error enumerating through names."); 1756 break; 1757 } 1758 } 1759 } 1760 } 1761 1762 // adoptFormat() takes ownership of the input Format object. 1763 // We need to clone the stack-allocated cf so that we do not attempt to delete cf. 1764 Format *cfClone = cf.clone(); 1765 msgfmt->adoptFormat("adopt", cfClone, status); 1766 1767 delete en; 1768 delete msgfmt; 1769 1770 msgfmt = new MessageFormat("'", status); 1771 if (msgfmt == NULL || U_FAILURE(status)) { 1772 errln("FAIL: Unable to create MessageFormat."); 1773 return; 1774 } 1775 if (msgfmt->usesNamedArguments()) { 1776 errln("FAIL: Unable to detect usage of named arguments."); 1777 } 1778 1779 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames() 1780 // on a MessageFormat without named arguments. 1781 msgfmt->setFormat("formatName", cf, status); 1782 if (U_FAILURE(status)) { 1783 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern."); 1784 } 1785 status = U_ZERO_ERROR; 1786 en = msgfmt->getFormatNames(status); 1787 if (U_FAILURE(status)) { 1788 errln("FAIL: Should work to get format names enumeration regardless of pattern."); 1789 } 1790 1791 delete en; 1792 delete msgfmt; 1793 } 1794 1795 void TestMessageFormat::testGetFormatNames() { 1796 IcuTestErrorCode errorCode(*this, "testGetFormatNames"); 1797 MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode); 1798 if(errorCode.logDataIfFailureAndReset("MessageFormat() failed")) { 1799 return; 1800 } 1801 LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode)); 1802 if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) { 1803 return; 1804 } 1805 const UnicodeString *name; 1806 name = names->snext(errorCode); 1807 if (name == NULL || errorCode.isFailure()) { 1808 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName()); 1809 errorCode.reset(); 1810 return; 1811 } 1812 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) { 1813 return; 1814 } 1815 name = names->snext(errorCode); 1816 if (name == NULL || errorCode.isFailure()) { 1817 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName()); 1818 errorCode.reset(); 1819 return; 1820 } 1821 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) { 1822 return; 1823 } 1824 name = names->snext(errorCode); 1825 if (name == NULL || errorCode.isFailure()) { 1826 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName()); 1827 errorCode.reset(); 1828 return; 1829 } 1830 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) { 1831 return; 1832 } 1833 name = names->snext(errorCode); 1834 if (name != NULL) { 1835 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name); 1836 return; 1837 } 1838 } 1839 1840 void TestMessageFormat::TestTrimArgumentName() { 1841 // ICU 4.8 allows and ignores white space around argument names and numbers. 1842 IcuTestErrorCode errorCode(*this, "TestTrimArgumentName"); 1843 MessageFormat m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode); 1844 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) { 1845 return; 1846 } 1847 Formattable args[1] = { (int32_t)2 }; 1848 FieldPosition ignore(0); 1849 UnicodeString result; 1850 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z", 1851 m.format(args, 1, result, ignore, errorCode)); 1852 1853 m.applyPattern("x { _oOo_ , number , integer } y", errorCode); 1854 UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_"); 1855 args[0].setLong(3); 1856 result.remove(); 1857 assertEquals("trim-named-arg format() failed", "x 3 y", 1858 m.format(&argName, args, 1, result, errorCode)); 1859 } 1860 1861 void TestMessageFormat::TestSelectOrdinal() { 1862 IcuTestErrorCode errorCode(*this, "TestSelectOrdinal"); 1863 // Test plural & ordinal together, 1864 // to make sure that we get the correct cached PluralSelector for each. 1865 MessageFormat m( 1866 "{0,plural,one{1 file}other{# files}}, " 1867 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}", 1868 Locale::getEnglish(), errorCode); 1869 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) { 1870 return; 1871 } 1872 Formattable args[1] = { (int32_t)21 }; 1873 FieldPosition ignore(0); 1874 UnicodeString result; 1875 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file", 1876 m.format(args, 1, result, ignore, errorCode), TRUE); 1877 1878 args[0].setLong(2); 1879 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file", 1880 m.format(args, 1, result.remove(), ignore, errorCode), TRUE); 1881 1882 args[0].setLong(1); 1883 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file", 1884 m.format(args, 1, result.remove(), ignore, errorCode), TRUE); 1885 1886 args[0].setLong(3); 1887 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file", 1888 m.format(args, 1, result.remove(), ignore, errorCode), TRUE); 1889 1890 errorCode.logDataIfFailureAndReset(""); 1891 } 1892 1893 void TestMessageFormat::TestDecimals() { 1894 IcuTestErrorCode errorCode(*this, "TestDecimals"); 1895 // Simple number replacement. 1896 MessageFormat m( 1897 "{0,plural,one{one meter}other{# meters}}", 1898 Locale::getEnglish(), errorCode); 1899 Formattable args[1] = { (int32_t)1 }; 1900 FieldPosition ignore; 1901 UnicodeString result; 1902 assertEquals("simple format(1)", "one meter", 1903 m.format(args, 1, result, ignore, errorCode), TRUE); 1904 1905 args[0] = (double)1.5; 1906 result.remove(); 1907 assertEquals("simple format(1.5)", "1.5 meters", 1908 m.format(args, 1, result, ignore, errorCode), TRUE); 1909 1910 // Simple but explicit. 1911 MessageFormat m0( 1912 "{0,plural,one{one meter}other{{0} meters}}", 1913 Locale::getEnglish(), errorCode); 1914 args[0] = (int32_t)1; 1915 result.remove(); 1916 assertEquals("explicit format(1)", "one meter", 1917 m0.format(args, 1, result, ignore, errorCode), TRUE); 1918 1919 args[0] = (double)1.5; 1920 result.remove(); 1921 assertEquals("explicit format(1.5)", "1.5 meters", 1922 m0.format(args, 1, result, ignore, errorCode), TRUE); 1923 1924 // With offset and specific simple format with optional decimals. 1925 MessageFormat m1( 1926 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}", 1927 Locale::getEnglish(), errorCode); 1928 args[0] = (int32_t)1; 1929 result.remove(); 1930 assertEquals("offset format(1)", "01 meters", 1931 m1.format(args, 1, result, ignore, errorCode), TRUE); 1932 1933 args[0] = (int32_t)2; 1934 result.remove(); 1935 assertEquals("offset format(1)", "another meter", 1936 m1.format(args, 1, result, ignore, errorCode), TRUE); 1937 1938 args[0] = (double)2.5; 1939 result.remove(); 1940 assertEquals("offset format(1)", "02.5 meters", 1941 m1.format(args, 1, result, ignore, errorCode), TRUE); 1942 1943 // With offset and specific simple format with forced decimals. 1944 MessageFormat m2( 1945 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}", 1946 Locale::getEnglish(), errorCode); 1947 args[0] = (int32_t)1; 1948 result.remove(); 1949 assertEquals("offset-decimals format(1)", "1.0 meters", 1950 m2.format(args, 1, result, ignore, errorCode), TRUE); 1951 1952 args[0] = (int32_t)2; 1953 result.remove(); 1954 assertEquals("offset-decimals format(1)", "2.0 meters", 1955 m2.format(args, 1, result, ignore, errorCode), TRUE); 1956 1957 args[0] = (double)2.5; 1958 result.remove(); 1959 assertEquals("offset-decimals format(1)", "2.5 meters", 1960 m2.format(args, 1, result, ignore, errorCode), TRUE); 1961 errorCode.reset(); 1962 } 1963 1964 #endif /* #if !UCONFIG_NO_FORMATTING */ 1965