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