1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************
10 * Modification History:
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 *******************************************************************/
18 #include "unicode/utypes.h"
20 #if !UCONFIG_NO_FORMATTING
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"
39 TestMessageFormat::runIndexedTest(int32_t index
, UBool exec
,
40 const char* &name
, char* /*par*/) {
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
);
77 void TestMessageFormat::testBug3()
79 double myNumber
= -123456;
80 DecimalFormat
*form
= 0;
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", ""),
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
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.");
145 FieldPosition
pos(FieldPosition::DONT_CARE
);
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.");
160 void TestMessageFormat::testBug1()
162 const double limit
[] = {0.0, 1.0, 2.0};
163 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
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");
177 void TestMessageFormat::testBug2()
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
));
189 logln("The output pattern is : " + fmt
->toPattern(result
));
190 if (pattern
!= result
) {
191 errln("MessageFormat::toPattern() failed.");
197 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
198 //----------------------------------------------------
200 //----------------------------------------------------
203 std::ostream
& operator<<(std::ostream
& stream
, const Formattable
& obj
);
205 #include "unicode/datefmt.h"
210 operator<<( IntlTest
& stream
,
211 const Formattable
& obj
)
213 static DateFormat
*defDateFormat
= 0;
215 UnicodeString buffer
;
216 switch(obj
.getType()) {
217 case Formattable::kDate
:
218 if (defDateFormat
== 0) {
219 defDateFormat
= DateFormat::createInstance();
221 defDateFormat
->format(obj
.getDate(), buffer
);
224 case Formattable::kDouble
:
226 sprintf( convert
, "%lf", obj
.getDouble() );
227 stream
<< convert
<< "D";
229 case Formattable::kLong
:
230 stream
<< obj
.getLong() << "L";
232 case Formattable::kString
:
233 stream
<< "\"" << obj
.getString(buffer
) << "\"";
235 case Formattable::kArray
:
237 const Formattable
* array
;
238 array
= obj
.getArray(count
);
240 for (i
=0; i
<count
; ++i
) stream
<< array
[i
] << ( (i
==(count
-1)) ? "" : ", " );
244 stream
<< "INVALID_Formattable";
248 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
251 void TestMessageFormat::PatternTest()
253 Formattable testArgs
[] = {
254 Formattable(double(1)), Formattable(double(3456)),
255 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate
)
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,#,##}",
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,#,##}"
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"
296 for (int32_t i
= 0; i
< 9; ++i
) {
297 //it_out << "\nPat in: " << testCases[i]);
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");
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.
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
);
322 //it_out << "Pat out: " << form->toPattern(buffer));
323 UnicodeString result
;
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");
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
] );
340 //it_out << "Result: " << result);
342 /* TODO: Look at this test and see if this is still a valid test */
343 logln("---------------- test parse ----------------");
345 form
->toPattern(buffer
);
346 logln("MSG pattern for parse: " + buffer
);
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
);
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
]));
365 errln("MessageFormat failed test #6");
371 void TestMessageFormat::sample()
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.");
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
);
393 void TestMessageFormat::testStaticFormat()
395 UErrorCode err
= U_ZERO_ERROR
;
396 Formattable arguments
[] = {
398 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
399 "a disturbance in the Force"
402 UnicodeString result
;
403 result
= MessageFormat::format(
404 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
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
);
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
);
425 /* When the default locale is tr, make sure that the pattern can still be parsed. */
426 void TestMessageFormat::TestTurkishCasing()
428 UErrorCode err
= U_ZERO_ERROR
;
429 Locale saveDefaultLocale
;
430 Locale::setDefault( Locale("tr"), err
);
432 Formattable arguments
[] = {
434 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
435 "a disturbance in the Force"
438 UnicodeString result
;
439 result
= MessageFormat::format(
440 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
446 if (U_FAILURE(err
)) {
447 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err
));
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
);
458 Locale::setDefault( saveDefaultLocale
, err
);
461 void TestMessageFormat::testSimpleFormat(/* char* par */)
463 logln("running TestMessageFormat::testSimpleFormat");
465 UErrorCode err
= U_ZERO_ERROR
;
467 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
468 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
469 Formattable testArgs3
[] = {(int32_t)12, "MyDisk"};
471 MessageFormat
* form
= new MessageFormat(
472 "The disk \"{1}\" contains {0} file(s).", err
);
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
));
481 ignore
.setField(FieldPosition::DONT_CARE
);
483 form
->format(testArgs2
, 2, string
, ignore
, err
);
484 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 1 file(s).") {
486 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string
+ " - " + u_errorName(err
));
489 ignore
.setField(FieldPosition::DONT_CARE
);
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
));
499 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
501 logln("running TestMessageFormat::testMsgFormatChoice");
503 UErrorCode err
= U_ZERO_ERROR
;
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?
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");
520 ignore
.setField(FieldPosition::DONT_CARE
);
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");
528 ignore
.setField(FieldPosition::DONT_CARE
);
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
));
541 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
543 logln("running TestMessageFormat::testMsgFormatPlural");
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
);
557 Formattable
testArgs1((int32_t)0);
558 FieldPosition
ignore(FieldPosition::DONT_CARE
);
559 UnicodeString numResult1
;
560 mfNum
->format(&testArgs1
, 1, numResult1
, ignore
, err
);
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
);
572 if ( numResult1
!= argNameResult
){
573 errln("TestMessageFormat::testMsgFormatPlural #1");
574 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
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."));
585 MessageFormat
* mfNum2
= new MessageFormat(t3
, Locale("uk"), err
);
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
);
593 if (U_FAILURE(err
)) {
594 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
595 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err
);
599 if ( numResult1
!= argNameResult
){
600 errln("TestMessageFormat::testMsgFormatPlural #2");
601 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
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."));
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
);
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");
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."));
633 void 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(),
639 if (U_FAILURE(errorCode
)) {
640 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode
));
643 UnicodeString expected
= UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
644 Formattable args
[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
646 &msgFmt
, args
, 2, expected
,
647 "MessageFormat with apostrophes in plural/select arguments failed:\n");
650 void TestMessageFormat::internalFormat(MessageFormat
* msgFmt
,
651 Formattable
* args
, int32_t numOfArgs
,
652 UnicodeString expected
, const char* errMsg
)
654 UnicodeString result
;
655 FieldPosition
ignore(FieldPosition::DONT_CARE
);
656 UErrorCode status
= U_ZERO_ERROR
;
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
) );
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");
671 MessageFormat
* TestMessageFormat::internalCreate(
672 UnicodeString pattern
,Locale locale
,UErrorCode
&status
, char* errMsg
)
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
);
684 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
686 logln("running TestMessageFormat::testMsgFormatSelect");
688 UErrorCode err
= U_ZERO_ERROR
;
690 UnicodeString
t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
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
)) {
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."};
706 for( int i
=0; i
< 3; i
++){
707 internalFormat( msgFmt1
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
712 //Quoted French Pattern
713 UnicodeString
t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
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
)) {
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."};
728 for( int i
=0; i
< 3; i
++){
729 internalFormat( msgFmt2
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
735 UnicodeString
t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
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
)) {
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."};
750 for( int i
=0; i
< 3; i
++){
751 internalFormat( msgFmt3
, testArgs
[i
], 1, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
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.");
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
)) {
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."};
773 for( int i
=0; i
< 3; i
++){
774 internalFormat( msgFmt4
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
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.");
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
)) {
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."};
798 for( int i
=0; i
< 4; i
++){
799 internalFormat( msgFmt5
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
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
)) {
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."
846 for( int i
=0; i
< 14; i
++){
847 internalFormat( msgFmt6
, testArgs
[i
], 4, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
853 //---------------------------------
855 //---------------------------------
857 void TestMessageFormat::testCopyConstructor()
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
);
867 logln("First test (operator ==): Passed!");
869 errln("TestMessageFormat::testCopyConstructor failed #1");
870 logln("First test (operator ==): Failed!");
872 if ( ((*x
== *y
) && (*y
== *x
)) &&
873 ((*x
!= *z
) && (*z
!= *x
)) &&
874 ((*y
!= *z
) && (*z
!= *y
)) )
875 logln("Second test (equals): Passed!");
877 errln("TestMessageFormat::testCopyConstructor failed #2");
878 logln("Second test (equals): Failed!");
887 void TestMessageFormat::testAssignment()
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
);
897 logln("First test (operator ==): Passed!");
899 errln( "TestMessageFormat::testAssignment failed #1");
900 logln("First test (operator ==): Failed!");
902 if ( ((*x
== *y
) && (*y
== *x
)) &&
903 ((*x
!= *z
) && (*z
!= *x
)) &&
904 ((*y
!= *z
) && (*z
!= *y
)) )
905 logln("Second test (equals): Passed!");
907 errln("TestMessageFormat::testAssignment failed #2");
908 logln("Second test (equals): Failed!");
916 void TestMessageFormat::testClone()
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();
926 logln("First test (operator ==): Passed!");
928 errln("TestMessageFormat::testClone failed #1");
929 logln("First test (operator ==): Failed!");
931 if ( ((*x
== *y
) && (*y
== *x
)) &&
932 ((*x
!= *z
) && (*z
!= *x
)) &&
933 ((*y
!= *z
) && (*z
!= *y
)) )
934 logln("Second test (equals): Passed!");
936 errln("TestMessageFormat::testClone failed #2");
937 logln("Second test (equals): Failed!");
945 void TestMessageFormat::testEquals()
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
);
951 errln( "TestMessageFormat::testEquals failed #1");
952 logln("First test (operator ==): Failed!");
957 void TestMessageFormat::testNotEquals()
959 UErrorCode success
= U_ZERO_ERROR
;
960 MessageFormat
x("There are {0} files on {1}", success
);
962 y
.setLocale(Locale("fr"));
964 errln( "TestMessageFormat::testEquals failed #1");
965 logln("First test (operator !=): Failed!");
968 y
.applyPattern("There are {0} files on {1} the disk", success
);
970 errln( "TestMessageFormat::testEquals failed #1");
971 logln("Second test (operator !=): Failed!");
976 void TestMessageFormat::testSetLocale()
978 UErrorCode err
= U_ZERO_ERROR
;
979 GregorianCalendar
cal(err
);
980 Formattable arguments
[] = {
982 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
986 UnicodeString result
;
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
+= ".";
1005 MessageFormat
msg( formatStr
, err
);
1007 FieldPosition
pos(FieldPosition::DONT_CARE
);
1008 result
= msg
.format(
1016 if (result
!= compareStrEng
) {
1017 dataerrln("*** MSG format err. - %s", u_errorName(err
));
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
;
1027 msg
.setLocale(Locale::getGerman());
1029 if (msg
.getLocale() != Locale::getGerman()) {
1030 errln("*** MSG getLocal err.");
1031 getLocale_ok
= FALSE
;
1034 msg
.applyPattern( formatStr
, err
);
1038 result
= msg
.format(
1046 if (result
== compareStrGer
) {
1047 logln("MSG setLocale tested.");
1049 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err
));
1053 logln("MSG getLocale tested.");
1057 void TestMessageFormat::testFormat()
1059 UErrorCode err
= U_ZERO_ERROR
;
1060 GregorianCalendar
cal(err
);
1062 const Formattable ftarray
[] =
1064 Formattable( UDate(8.71068e+011), Formattable::kIsDate
)
1066 const int32_t ft_cnt
= UPRV_LENGTHOF(ftarray
);
1067 Formattable
ft_arr( ftarray
, ft_cnt
);
1069 Formattable
* fmt
= new Formattable(UDate(8.71068e+011), Formattable::kIsDate
);
1071 UnicodeString result
;
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.";
1078 MessageFormat
msg( formatStr
, err
);
1079 FieldPosition
fp(FieldPosition::DONT_CARE
);
1083 result
= msg
.format(
1090 if (err
!= U_ILLEGAL_ARGUMENT_ERROR
) {
1091 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err
));
1097 result
= msg
.format(
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
));
1109 logln("MSG format( Formattable&, ... ) tested.");
1116 void TestMessageFormat::testParse()
1118 UErrorCode err
= U_ZERO_ERROR
;
1120 UnicodeString msgFormatString
= "{0} =sep= {1}";
1121 MessageFormat
msg( msgFormatString
, err
);
1122 UnicodeString source
= "abc =sep= def";
1123 UnicodeString tmp1
, tmp2
;
1125 Formattable
* fmt_arr
= msg
.parse( source
, count
, err
);
1126 if (U_FAILURE(err
) || (!fmt_arr
)) {
1127 errln("*** MSG parse (ustring, count, err) error.");
1129 logln("MSG parse -- count: %d", count
);
1131 errln("*** MSG parse (ustring, count, err) count err.");
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.");
1139 errln("*** MSG parse (ustring, count, err) result err.");
1145 ParsePosition
pp(0);
1147 fmt_arr
= msg
.parse( source
, pp
, count
);
1148 if ((pp
== 0) || (!fmt_arr
)) {
1149 errln("*** MSG parse (ustring, parsepos., count) error.");
1151 logln("MSG parse -- count: %d", count
);
1153 errln("*** MSG parse (ustring, parsepos., count) count err.");
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.");
1161 errln("*** MSG parse (ustring, parsepos., count) result err.");
1170 msg
.parseObject( source
, fmta
, pp
);
1172 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1174 logln("MSG parse -- count: %d", count
);
1175 fmta
.getArray(count
);
1177 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
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.");
1185 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1192 void TestMessageFormat::testAdopt()
1194 UErrorCode err
= U_ZERO_ERROR
;
1196 UnicodeString
formatStr("{0,date},{1},{2,number}", "");
1197 UnicodeString
formatStrChange("{0,number},{1,number},{2,date}", "");
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
));
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;
1213 UnicodeString patCmp
;
1214 UnicodeString patAct
;
1215 Format
** formatsToAdopt
;
1217 if (!formats
|| !formatsCmp
|| (count
<= 0) || (count
!= countCmp
)) {
1218 dataerrln("Error getting Formats");
1224 for (i
= 0; i
< count
; i
++) {
1227 if ((a
!= NULL
) && (b
!= NULL
)) {
1232 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1233 errln("(a != NULL) || (b != NULL)");
1238 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1240 formatsChg
= msg
.getFormats(countChg
); // tested function
1241 if (!formatsChg
|| (countChg
!= count
)) {
1242 errln("Error getting Formats");
1248 for (i
= 0; i
< count
; i
++) {
1251 if ((a
!= NULL
) && (b
!= NULL
)) {
1253 logln("formatsChg == formatsCmp at index %d", i
);
1259 errln("*** MSG getFormats diff err.");
1263 logln("MSG getFormats tested.");
1265 msg
.setFormats( formatsCmp
, countCmp
); //tested function
1267 formatsAct
= msg
.getFormats(countAct
);
1268 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1269 errln("Error getting Formats");
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.");
1281 for (i
= 0; i
< countAct
; i
++) {
1284 if ((a
!= NULL
) && (b
!= NULL
)) {
1286 logln("formatsAct != formatsCmp at index %d", i
);
1290 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1291 errln("(a != NULL) || (b != NULL)");
1295 logln("MSG setFormats tested.");
1299 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1301 formatsToAdopt
= new Format
* [countCmp
];
1302 if (!formatsToAdopt
) {
1303 errln("memory allocation error");
1307 for (i
= 0; i
< countCmp
; i
++) {
1308 if (formatsCmp
[i
] == NULL
) {
1309 formatsToAdopt
[i
] = NULL
;
1311 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1312 if (!formatsToAdopt
[i
]) {
1313 errln("Can't clone format at index %d", i
);
1318 msg
.adoptFormats( formatsToAdopt
, countCmp
); // function to test
1319 delete[] formatsToAdopt
;
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()));
1325 formatsAct
= msg
.getFormats(countAct
);
1326 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1327 errln("Error getting Formats");
1331 for (i
= 0; i
< countAct
; i
++) {
1334 if ((a
!= NULL
) && (b
!= NULL
)) {
1339 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1340 errln("(a != NULL) || (b != NULL)");
1344 logln("MSG adoptFormats tested.");
1348 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1350 formatsToAdopt
= new Format
* [countCmp
];
1351 if (!formatsToAdopt
) {
1352 errln("memory allocation error");
1356 for (i
= 0; i
< countCmp
; i
++) {
1357 if (formatsCmp
[i
] == NULL
) {
1358 formatsToAdopt
[i
] = NULL
;
1360 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1361 if (!formatsToAdopt
[i
]) {
1362 errln("Can't clone format at index %d", i
);
1368 for ( i
= 0; i
< countCmp
; i
++ ) {
1369 msg
.adoptFormat( i
, formatsToAdopt
[i
] ); // function to test
1371 delete[] formatsToAdopt
; // array itself not needed in this case;
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()));
1377 formatsAct
= msg
.getFormats(countAct
);
1378 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1379 errln("Error getting Formats");
1383 for (i
= 0; i
< countAct
; i
++) {
1386 if ((a
!= NULL
) && (b
!= NULL
)) {
1391 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1392 errln("(a != NULL) || (b != NULL)");
1396 logln("MSG adoptFormat tested.");
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*.
1405 static void _testCopyConstructor2()
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
);
1415 MessageFormat
* fmt1
= new MessageFormat( formatStr
, status
);
1416 MessageFormat
* fmt2
= NULL
;
1417 MessageFormat
* fmt3
= NULL
;
1418 MessageFormat
* fmt4
= NULL
;
1421 it_err("testCopyConstructor2: (fmt1 != NULL)");
1425 fmt2
= new MessageFormat( *fmt1
);
1426 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1429 it_err("testCopyConstructor2: (fmt2 != NULL)");
1433 fmt3
= (MessageFormat
*) fmt1
->clone();
1434 fmt4
= (MessageFormat
*) fmt2
->clone();
1437 it_err("testCopyConstructor2: (fmt3 != NULL)");
1441 it_err("testCopyConstructor2: (fmt4 != NULL)");
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
);
1457 void TestMessageFormat::testCopyConstructor2() {
1458 _testCopyConstructor2();
1462 * Verify that MessageFormat accomodates more than 10 arguments and
1463 * more than 10 subformats.
1465 void 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
));
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"),
1494 const int32_t ARGS_LENGTH
= UPRV_LENGTHOF(ARGS
);
1495 Formattable
ARGS_OBJ(ARGS
, ARGS_LENGTH
);
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
) {
1510 errln((UnicodeString
)"FAIL: Got " + result
+
1511 ", expected " + expected
);
1515 // test RBNF extensions to message format
1516 void TestMessageFormat::TestRBNF(void) {
1517 // WARNING: this depends on the RBNF formats for en_US
1518 Locale
locale("en", "US", "");
1520 UErrorCode ec
= U_ZERO_ERROR
;
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",
1527 int32_t values_count
= UPRV_LENGTHOF(values
);
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.",
1537 int32_t formats_count
= UPRV_LENGTHOF(formats
);
1539 Formattable args
[1];
1541 NumberFormat
* numFmt
= NumberFormat::createInstance(locale
, ec
);
1542 if (U_FAILURE(ec
)) {
1543 dataerrln("Error calling NumberFormat::createInstance()");
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
] + "'");
1551 for (int j
= 0; j
< values_count
; ++j
) {
1553 numFmt
->parse(values
[j
], args
[0], ec
);
1554 if (U_FAILURE(ec
)) {
1555 errln((UnicodeString
)"Failed to parse test argument " + values
[j
]);
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
));
1563 Formattable
* parseResult
= fmt
->parse(result
, count
, ec
);
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]));
1569 delete []parseResult
;
1577 UnicodeString
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());
1589 void 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().");
1596 if (adr_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1597 errln("wrong value from adr_mp->getApostropheMode().");
1601 UnicodeString tuples
[] = {
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"
1611 int32_t tuples_count
= UPRV_LENGTHOF(tuples
);
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",
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
)));
1629 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
1630 void 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";
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().");
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().");
1648 Formattable zero0
[] = { (int32_t)0 };
1649 FieldPosition
fieldpos(FieldPosition::DONT_CARE
);
1650 UnicodeString buffer1
, buffer2
;
1651 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1653 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1654 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1656 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1658 // Message with choice argument which contains a nested simple argument.
1659 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
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
));
1668 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
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
));
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.
1680 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1681 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
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}",
1691 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1692 const char* patterns
[] = { // pattern, expected pattern
1703 "{'a{}'a}'a", "{'a{}'a}''a",
1705 "'} '{'}'", "'} '{'}''",
1706 "'} {{{''", "'} {{{'''",
1708 int32_t pattern_count
= UPRV_LENGTHOF(patterns
);
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;
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;
1722 sprintf(buf
, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i
/2, patterns
[i
], patterns
[i
+1], buf2
);
1728 void 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
));
1736 if (!msgfmt
->usesNamedArguments()) {
1737 errln("FAIL: Unable to detect usage of named arguments.");
1739 const double limit
[] = {0.0, 1.0, 2.0};
1740 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
1743 ChoiceFormat
cf(limit
, formats
, 3);
1745 msgfmt
->setFormat("set", cf
, status
);
1747 StringEnumeration
*en
= msgfmt
->getFormatNames(status
);
1748 if (en
== NULL
|| U_FAILURE(status
)) {
1749 errln("FAIL: Unable to get format names enumeration.");
1753 count
= en
->count(status
);
1754 if (U_FAILURE(status
)) {
1755 errln("FAIL: Unable to get format name enumeration count.");
1757 for (int32_t i
= 0; i
< count
; i
++) {
1759 if (U_FAILURE(status
)) {
1760 errln("FAIL: Error enumerating through names.");
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
);
1775 msgfmt
= new MessageFormat("'", status
);
1776 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1777 errln("FAIL: Unable to create MessageFormat.");
1780 if (msgfmt
->usesNamedArguments()) {
1781 errln("FAIL: Unable to detect usage of named arguments.");
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.");
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.");
1800 void 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")) {
1806 LocalPointer
<StringEnumeration
> names(msgfmt
.getFormatNames(errorCode
));
1807 if(errorCode
.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1810 const UnicodeString
*name
;
1811 name
= names
->snext(errorCode
);
1812 if (name
== NULL
|| errorCode
.isFailure()) {
1813 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode
.errorName());
1817 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name
)) {
1820 name
= names
->snext(errorCode
);
1821 if (name
== NULL
|| errorCode
.isFailure()) {
1822 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode
.errorName());
1826 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name
)) {
1829 name
= names
->snext(errorCode
);
1830 if (name
== NULL
|| errorCode
.isFailure()) {
1831 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode
.errorName());
1835 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name
)) {
1838 name
= names
->snext(errorCode
);
1840 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name
);
1845 void 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")) {
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
));
1858 m
.applyPattern("x { _oOo_ , number , integer } y", errorCode
);
1859 UnicodeString argName
= UNICODE_STRING_SIMPLE("_oOo_");
1862 assertEquals("trim-named-arg format() failed", "x 3 y",
1863 m
.format(&argName
, args
, 1, result
, errorCode
));
1866 void 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.
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")) {
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
);
1884 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1885 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1888 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1889 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1892 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1893 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1895 errorCode
.logDataIfFailureAndReset("");
1898 void TestMessageFormat::TestDecimals() {
1899 IcuTestErrorCode
errorCode(*this, "TestDecimals");
1900 // Simple number replacement.
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
);
1910 args
[0] = (double)1.5;
1912 assertEquals("simple format(1.5)", "1.5 meters",
1913 m
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1915 // Simple but explicit.
1917 "{0,plural,one{one meter}other{{0} meters}}",
1918 Locale::getEnglish(), errorCode
);
1919 args
[0] = (int32_t)1;
1921 assertEquals("explicit format(1)", "one meter",
1922 m0
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1924 args
[0] = (double)1.5;
1926 assertEquals("explicit format(1.5)", "1.5 meters",
1927 m0
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1929 // With offset and specific simple format with optional decimals.
1931 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1932 Locale::getEnglish(), errorCode
);
1933 args
[0] = (int32_t)1;
1935 assertEquals("offset format(1)", "01 meters",
1936 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1938 args
[0] = (int32_t)2;
1940 assertEquals("offset format(1)", "another meter",
1941 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1943 args
[0] = (double)2.5;
1945 assertEquals("offset format(1)", "02.5 meters",
1946 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1948 // With offset and specific simple format with forced decimals.
1950 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1951 Locale::getEnglish(), errorCode
);
1952 args
[0] = (int32_t)1;
1954 assertEquals("offset-decimals format(1)", "1.0 meters",
1955 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1957 args
[0] = (int32_t)2;
1959 assertEquals("offset-decimals format(1)", "2.0 meters",
1960 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1962 args
[0] = (double)2.5;
1964 assertEquals("offset-decimals format(1)", "2.5 meters",
1965 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1969 void TestMessageFormat::TestArgIsPrefixOfAnother() {
1970 IcuTestErrorCode
errorCode(*this, "TestArgIsPrefixOfAnother");
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
));
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
));
1992 MessageFormat
mf3("{aa} {aaa}", Locale::getEnglish(), errorCode
);
1993 assertEquals("aa aaa", "AB ABC", mf3
.format(argNames
+ 1, args
+ 1, 2, result
.remove(), errorCode
));
1996 #endif /* #if !UCONFIG_NO_FORMATTING */