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