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
26 #include "unicode/format.h"
27 #include "unicode/decimfmt.h"
28 #include "unicode/localpointer.h"
29 #include "unicode/locid.h"
30 #include "unicode/msgfmt.h"
31 #include "unicode/numfmt.h"
32 #include "unicode/choicfmt.h"
33 #include "unicode/messagepattern.h"
34 #include "unicode/selfmt.h"
35 #include "unicode/gregocal.h"
36 #include "unicode/strenum.h"
40 TestMessageFormat::runIndexedTest(int32_t index
, UBool exec
,
41 const char* &name
, char* /*par*/) {
43 TESTCASE_AUTO(testBug1
);
44 TESTCASE_AUTO(testBug2
);
45 TESTCASE_AUTO(sample
);
46 TESTCASE_AUTO(PatternTest
);
47 TESTCASE_AUTO(testStaticFormat
);
48 TESTCASE_AUTO(testSimpleFormat
);
49 TESTCASE_AUTO(testMsgFormatChoice
);
50 TESTCASE_AUTO(testCopyConstructor
);
51 TESTCASE_AUTO(testAssignment
);
52 TESTCASE_AUTO(testClone
);
53 TESTCASE_AUTO(testEquals
);
54 TESTCASE_AUTO(testNotEquals
);
55 TESTCASE_AUTO(testSetLocale
);
56 TESTCASE_AUTO(testFormat
);
57 TESTCASE_AUTO(testParse
);
58 TESTCASE_AUTO(testAdopt
);
59 TESTCASE_AUTO(testCopyConstructor2
);
60 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats
);
61 TESTCASE_AUTO(TestRBNF
);
62 TESTCASE_AUTO(TestTurkishCasing
);
63 TESTCASE_AUTO(testAutoQuoteApostrophe
);
64 TESTCASE_AUTO(testMsgFormatPlural
);
65 TESTCASE_AUTO(testMsgFormatSelect
);
66 TESTCASE_AUTO(testApostropheInPluralAndSelect
);
67 TESTCASE_AUTO(TestApostropheMode
);
68 TESTCASE_AUTO(TestCompatibleApostrophe
);
69 TESTCASE_AUTO(testCoverage
);
70 TESTCASE_AUTO(testGetFormatNames
);
71 TESTCASE_AUTO(TestTrimArgumentName
);
72 TESTCASE_AUTO(TestSelectOrdinal
);
73 TESTCASE_AUTO(TestDecimals
);
74 TESTCASE_AUTO(TestArgIsPrefixOfAnother
);
75 TESTCASE_AUTO(TestMessageFormatNumberSkeleton
);
76 TESTCASE_AUTO(TestMessageFormatDateSkeleton
);
77 TESTCASE_AUTO(TestMessageFormatTimeSkeleton
);
81 void TestMessageFormat::testBug3()
83 double myNumber
= -123456;
84 DecimalFormat
*form
= 0;
93 Locale("de", "AT", ""),
94 Locale("de", "CH", ""),
95 Locale("el", "", ""), // 10
96 Locale("en", "CA", ""),
97 Locale("en", "GB", ""),
98 Locale("en", "IE", ""),
99 Locale("en", "US", ""),
100 Locale("es", "", ""),
101 Locale("et", "", ""),
102 Locale("fi", "", ""),
103 Locale("fr", "", ""),
104 Locale("fr", "BE", ""),
105 Locale("fr", "CA", ""), // 20
106 Locale("fr", "CH", ""),
107 Locale("he", "", ""),
108 Locale("hr", "", ""),
109 Locale("hu", "", ""),
110 Locale("is", "", ""),
111 Locale("it", "", ""),
112 Locale("it", "CH", ""),
113 Locale("ja", "", ""),
114 Locale("ko", "", ""),
115 Locale("lt", "", ""), // 30
116 Locale("lv", "", ""),
117 Locale("mk", "", ""),
118 Locale("nl", "", ""),
119 Locale("nl", "BE", ""),
120 Locale("no", "", ""),
121 Locale("pl", "", ""),
122 Locale("pt", "", ""),
123 Locale("ro", "", ""),
124 Locale("ru", "", ""),
125 Locale("sh", "", ""), // 40
126 Locale("sk", "", ""),
127 Locale("sl", "", ""),
128 Locale("sq", "", ""),
129 Locale("sr", "", ""),
130 Locale("sv", "", ""),
131 Locale("tr", "", ""),
132 Locale("uk", "", ""),
133 Locale("zh", "", ""),
134 Locale("zh", "TW", "") // 49
137 for (i
= 0; i
< 49; i
++) {
138 UnicodeString buffer
;
139 logln(locale
[i
].getDisplayName(buffer
));
140 UErrorCode success
= U_ZERO_ERROR
;
141 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
142 form
= (DecimalFormat
*)NumberFormat::createInstance(locale
[i
], success
);
143 if (U_FAILURE(success
)) {
144 errln("Err: Number Format ");
145 logln("Number format creation failed.");
149 FieldPosition
pos(FieldPosition::DONT_CARE
);
151 form
->format(myNumber
, buffer
, pos
);
152 success
= U_ZERO_ERROR
;
153 ParsePosition parsePos
;
154 form
->parse(buffer
, result
, parsePos
);
155 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result
) + UnicodeString("[supposed output for result]"));
156 if (U_FAILURE(success
)) {
157 errln("Err: Number Format parse");
158 logln("Number format parse failed.");
164 void TestMessageFormat::testBug1()
166 const double limit
[] = {0.0, 1.0, 2.0};
167 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
170 ChoiceFormat
*cf
= new ChoiceFormat(limit
, formats
, 3);
171 FieldPosition
status(FieldPosition::DONT_CARE
);
172 UnicodeString toAppendTo
;
173 cf
->format((int32_t)1, toAppendTo
, status
);
174 if (toAppendTo
!= "1.0<=Arg<2.0") {
175 errln("ChoiceFormat cmp in testBug1");
181 void TestMessageFormat::testBug2()
183 UErrorCode status
= U_ZERO_ERROR
;
184 UnicodeString result
;
185 // {sfb} use double format in pattern, so result will match (not strictly necessary)
186 const UnicodeString pattern
= "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
187 logln("The input pattern : " + pattern
);
188 LocalPointer
<MessageFormat
> fmt(new MessageFormat(pattern
, status
));
189 if (U_FAILURE(status
)) {
190 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status
));
193 logln("The output pattern is : " + fmt
->toPattern(result
));
194 if (pattern
!= result
) {
195 errln("MessageFormat::toPattern() failed.");
201 //----------------------------------------------------
203 //----------------------------------------------------
206 std::ostream
& operator<<(std::ostream
& stream
, const Formattable
& obj
);
208 #include "unicode/datefmt.h"
213 operator<<( IntlTest
& stream
,
214 const Formattable
& obj
)
216 static DateFormat
*defDateFormat
= 0;
218 UnicodeString buffer
;
219 switch(obj
.getType()) {
220 case Formattable::kDate
:
221 if (defDateFormat
== 0) {
222 defDateFormat
= DateFormat::createInstance();
224 defDateFormat
->format(obj
.getDate(), buffer
);
227 case Formattable::kDouble
:
229 sprintf( convert
, "%lf", obj
.getDouble() );
230 stream
<< convert
<< "D";
232 case Formattable::kLong
:
233 stream
<< obj
.getLong() << "L";
235 case Formattable::kString
:
236 stream
<< "\"" << obj
.getString(buffer
) << "\"";
238 case Formattable::kArray
:
240 const Formattable
* array
;
241 array
= obj
.getArray(count
);
243 for (i
=0; i
<count
; ++i
) stream
<< array
[i
] << ( (i
==(count
-1)) ? "" : ", " );
247 stream
<< "INVALID_Formattable";
251 #endif /* defined(_DEBUG) */
254 void TestMessageFormat::PatternTest()
256 Formattable testArgs
[] = {
257 Formattable(double(1)), Formattable(double(3456)),
258 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate
)
260 UnicodeString testCases
[] = {
261 "Quotes '', '{', 'a' {0} '{0}'",
262 "Quotes '', '{', 'a' {0,number} '{0}'",
263 "'{'1,number,'#',##} {1,number,'#',##}",
264 "There are {1} files on {2} at {3}.",
265 "On {2}, there are {1} files, with {0,number,currency}.",
266 "'{1,number,percent}', {1,number,percent},",
267 "'{1,date,full}', {1,date,full},",
268 "'{3,date,full}', {3,date,full},",
269 "'{1,number,#,##}' {1,number,#,##}",
272 // ICU 4.8 returns the original pattern (testCases),
273 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
274 /*UnicodeString testResultPatterns[] = {
275 "Quotes '', '{', a {0} '{'0}",
276 "Quotes '', '{', a {0,number} '{'0}",
277 "'{'1,number,#,##} {1,number,'#'#,##}",
278 "There are {1} files on {2} at {3}.",
279 "On {2}, there are {1} files, with {0,number,currency}.",
280 "'{'1,number,percent}, {1,number,percent},",
281 "'{'1,date,full}, {1,date,full},",
282 "'{'3,date,full}, {3,date,full},",
283 "'{'1,number,#,##} {1,number,#,##}"
286 UnicodeString testResultStrings
[] = {
287 "Quotes ', {, 'a' 1 {0}",
288 "Quotes ', {, 'a' 1 {0}",
289 "{1,number,'#',##} #34,56",
290 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.",
291 "On Disk, there are 3,456 files, with $1.00.",
292 "{1,number,percent}, 345,600%,",
293 "{1,date,full}, Wednesday, December 31, 1969,",
294 "{3,date,full}, Monday, January 12, 1970,",
295 "{1,number,#,##} 34,56"
299 for (int32_t i
= 0; i
< 9; ++i
) {
300 //it_out << "\nPat in: " << testCases[i]);
302 LocalPointer
<MessageFormat
> form
;
303 UErrorCode success
= U_ZERO_ERROR
;
304 UnicodeString buffer
;
305 form
.adoptInstead(new MessageFormat(testCases
[i
], Locale::getUS(), success
));
306 if (U_FAILURE(success
)) {
307 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success
));
308 logln(((UnicodeString
)"MessageFormat for ") + testCases
[i
] + " creation failed.\n");
311 // ICU 4.8 returns the original pattern (testCases),
312 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
313 if (form
->toPattern(buffer
) != testCases
[i
]) {
314 // Note: An alternative test would be to build MessagePattern objects for
315 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
317 // (Too much trouble...)
318 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i
);
319 //form->toPattern(buffer);
320 errln(((UnicodeString
)" Orig: ") + testCases
[i
]);
321 errln(((UnicodeString
)" Exp: ") + testCases
[i
]);
322 errln(((UnicodeString
)" Got: ") + buffer
);
325 //it_out << "Pat out: " << form->toPattern(buffer));
326 UnicodeString result
;
328 FieldPosition
fieldpos(FieldPosition::DONT_CARE
);
329 form
->format(testArgs
, count
, result
, fieldpos
, success
);
330 if (U_FAILURE(success
)) {
331 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success
));
332 logln("TestMessageFormat::PatternTest failed test #3");
335 if (result
!= testResultStrings
[i
]) {
336 errln("TestMessageFormat::PatternTest failed test #4");
337 logln("TestMessageFormat::PatternTest failed #4.");
338 logln(UnicodeString(" Result: ") + result
);
339 logln(UnicodeString(" Expected: ") + testResultStrings
[i
] );
343 //it_out << "Result: " << result);
345 /* TODO: Look at this test and see if this is still a valid test */
346 logln("---------------- test parse ----------------");
348 form
->toPattern(buffer
);
349 logln("MSG pattern for parse: " + buffer
);
351 int32_t parseCount
= 0;
352 Formattable
* values
= form
->parse(result
, parseCount
, success
);
353 if (U_FAILURE(success
)) {
354 errln("MessageFormat failed test #5");
355 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success
);
356 } else if (parseCount
!= count
) {
357 errln("MSG count not %d as expected. Got %d", count
, parseCount
);
359 UBool failed
= FALSE
;
360 for (int32_t j
= 0; j
< parseCount
; ++j
) {
361 if (values
== 0 || testArgs
[j
] != values
[j
]) {
362 errln(((UnicodeString
)"MSG testargs[") + j
+ "]: " + toString(testArgs
[j
]));
363 errln(((UnicodeString
)"MSG values[") + j
+ "] : " + toString(values
[j
]));
368 errln("MessageFormat failed test #6");
373 void TestMessageFormat::sample()
375 MessageFormat
*form
= 0;
376 UnicodeString buffer1
, buffer2
;
377 UErrorCode success
= U_ZERO_ERROR
;
378 form
= new MessageFormat("There are {0} files on {1}", success
);
379 if (U_FAILURE(success
)) {
380 errln("Err: Message format creation failed");
381 logln("Sample message format creation failed.");
384 UnicodeString
abc("abc");
385 UnicodeString
def("def");
386 Formattable testArgs1
[] = { abc
, def
};
387 FieldPosition
fieldpos(FieldPosition::DONT_CARE
);
388 assertEquals("format",
389 "There are abc files on def",
390 form
->format(testArgs1
, 2, buffer2
, fieldpos
, success
));
391 assertSuccess("format", success
);
395 void TestMessageFormat::testStaticFormat()
397 UErrorCode err
= U_ZERO_ERROR
;
398 Formattable arguments
[] = {
400 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
401 "a disturbance in the Force"
404 UnicodeString result
;
405 result
= MessageFormat::format(
406 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
412 if (U_FAILURE(err
)) {
413 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err
));
414 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err
);
418 const UnicodeString
expected(
419 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
420 if (result
!= expected
) {
421 errln("TestMessageFormat::testStaticFormat failed on test");
422 logln( UnicodeString(" Result: ") + result
);
423 logln( UnicodeString(" Expected: ") + expected
);
427 /* When the default locale is tr, make sure that the pattern can still be parsed. */
428 void TestMessageFormat::TestTurkishCasing()
430 UErrorCode err
= U_ZERO_ERROR
;
431 Locale saveDefaultLocale
;
432 Locale::setDefault( Locale("tr"), err
);
434 Formattable arguments
[] = {
436 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
437 "a disturbance in the Force"
440 UnicodeString result
;
441 result
= MessageFormat::format(
442 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
448 if (U_FAILURE(err
)) {
449 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err
));
453 const UnicodeString
expected(
454 "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", "");
455 if (result
!= expected
) {
456 errln("TestTurkishCasing failed on test");
457 errln( UnicodeString(" Result: ") + result
);
458 errln( UnicodeString(" Expected: ") + expected
);
460 Locale::setDefault( saveDefaultLocale
, err
);
463 void TestMessageFormat::testSimpleFormat(/* char* par */)
465 logln("running TestMessageFormat::testSimpleFormat");
467 UErrorCode err
= U_ZERO_ERROR
;
469 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
470 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
471 Formattable testArgs3
[] = {(int32_t)12, "MyDisk"};
473 MessageFormat
* form
= new MessageFormat(
474 "The disk \"{1}\" contains {0} file(s).", err
);
476 UnicodeString string
;
477 FieldPosition
ignore(FieldPosition::DONT_CARE
);
478 form
->format(testArgs1
, 2, string
, ignore
, err
);
479 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 0 file(s).") {
480 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err
));
483 ignore
.setField(FieldPosition::DONT_CARE
);
485 form
->format(testArgs2
, 2, string
, ignore
, err
);
486 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 1 file(s).") {
488 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string
+ " - " + u_errorName(err
));
491 ignore
.setField(FieldPosition::DONT_CARE
);
493 form
->format(testArgs3
, 2, string
, ignore
, err
);
494 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 12 file(s).") {
495 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string
+ " - " + u_errorName(err
));
501 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
503 logln("running TestMessageFormat::testMsgFormatChoice");
505 UErrorCode err
= U_ZERO_ERROR
;
507 MessageFormat
* form
= new MessageFormat("The disk \"{1}\" contains {0}.", err
);
508 double filelimits
[] = {0,1,2};
509 UnicodeString filepart
[] = {"no files","one file","{0,number} files"};
510 ChoiceFormat
* fileform
= new ChoiceFormat(filelimits
, filepart
, 3);
511 form
->setFormat(1,*fileform
); // NOT zero, see below
512 //is the format adopted?
514 FieldPosition
ignore(FieldPosition::DONT_CARE
);
515 UnicodeString string
;
516 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
517 form
->format(testArgs1
, 2, string
, ignore
, err
);
518 if (string
!= "The disk \"MyDisk\" contains no files.") {
519 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
522 ignore
.setField(FieldPosition::DONT_CARE
);
524 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
525 form
->format(testArgs2
, 2, string
, ignore
, err
);
526 if (string
!= "The disk \"MyDisk\" contains one file.") {
527 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
530 ignore
.setField(FieldPosition::DONT_CARE
);
532 Formattable testArgs3
[] = {(int32_t)1273, "MyDisk"};
533 form
->format(testArgs3
, 2, string
, ignore
, err
);
534 if (string
!= "The disk \"MyDisk\" contains 1,273 files.") {
535 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err
));
543 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
545 logln("running TestMessageFormat::testMsgFormatPlural");
547 UErrorCode err
= U_ZERO_ERROR
;
548 UnicodeString
t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
549 UnicodeString
t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
550 UnicodeString
t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory.");
551 UnicodeString
t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory.");
552 UnicodeString
t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.");
553 MessageFormat
* mfNum
= new MessageFormat(t1
, Locale("fr"), err
);
554 if (U_FAILURE(err
)) {
555 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err
));
556 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
559 Formattable
testArgs1((int32_t)0);
560 FieldPosition
ignore(FieldPosition::DONT_CARE
);
561 UnicodeString numResult1
;
562 mfNum
->format(&testArgs1
, 1, numResult1
, ignore
, err
);
564 MessageFormat
* mfAlpha
= new MessageFormat(t2
, Locale("fr"), err
);
565 UnicodeString argName
[] = {UnicodeString("argument")};
566 UnicodeString argNameResult
;
567 mfAlpha
->format(argName
, &testArgs1
, 1, argNameResult
, err
);
568 if (U_FAILURE(err
)) {
569 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err
));
570 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
574 if ( numResult1
!= argNameResult
){
575 errln("TestMessageFormat::testMsgFormatPlural #1");
576 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
578 if ( numResult1
!= UnicodeString("C\'est 0 fichier dans la liste.")) {
579 errln("TestMessageFormat::testMsgFormatPlural #1");
580 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
587 MessageFormat
* mfNum2
= new MessageFormat(t3
, Locale("uk"), err
);
589 Formattable
testArgs2((int32_t)4);
590 mfNum2
->format(&testArgs2
, 1, numResult1
, ignore
, err
);
591 MessageFormat
* mfAlpha2
= new MessageFormat(t4
, Locale("uk"), err
);
592 argNameResult
.remove();
593 mfAlpha2
->format(argName
, &testArgs2
, 1, argNameResult
, err
);
595 if (U_FAILURE(err
)) {
596 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
597 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err
);
601 if ( numResult1
!= argNameResult
){
602 errln("TestMessageFormat::testMsgFormatPlural #2");
603 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
605 if ( numResult1
!= UnicodeString("There are 4,0 zavoda in the directory.")) {
606 errln("TestMessageFormat::testMsgFormatPlural #2");
607 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
615 MessageFormat
* msgFmt
= new MessageFormat(t5
, Locale("fr"), err
);
616 if (U_FAILURE(err
)) {
617 errln("TestMessageFormat::test nested PluralFormat with argumentName");
618 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err
);
622 Formattable
testArgs3((int32_t)0);
623 argNameResult
.remove();
624 msgFmt
->format(&testArgs3
, 1, argNameResult
, ignore
, err
);
625 if (U_FAILURE(err
)) {
626 errln("TestMessageFormat::test nested PluralFormat with argumentName");
628 if ( argNameResult
!= UnicodeString("C'est 0,0 fichier dans la liste.")) {
629 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult
);
630 logln(UnicodeString("The unexpected nested named PluralFormat."));
635 void TestMessageFormat::testApostropheInPluralAndSelect() {
636 UErrorCode errorCode
= U_ZERO_ERROR
;
637 MessageFormat
msgFmt(UNICODE_STRING_SIMPLE(
638 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"),
639 Locale::getEnglish(),
641 if (U_FAILURE(errorCode
)) {
642 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode
));
645 UnicodeString expected
= UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
646 Formattable args
[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
648 &msgFmt
, args
, 2, expected
,
649 "MessageFormat with apostrophes in plural/select arguments failed:\n");
652 void TestMessageFormat::internalFormat(MessageFormat
* msgFmt
,
653 Formattable
* args
, int32_t numOfArgs
,
654 UnicodeString expected
, const char* errMsg
)
656 UnicodeString result
;
657 FieldPosition
ignore(FieldPosition::DONT_CARE
);
658 UErrorCode status
= U_ZERO_ERROR
;
660 //Format with passed arguments
661 msgFmt
->format( args
, numOfArgs
, result
, ignore
, status
);
662 if (U_FAILURE(status
)) {
663 dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
665 //Compare expected with obtained result
666 if ( result
!= expected
) {
667 UnicodeString err
= UnicodeString(errMsg
);
668 err
+= UnicodeString(":Unexpected Result \n Expected: " + expected
+ "\n Obtained: " + result
+ "\n");
673 MessageFormat
* TestMessageFormat::internalCreate(
674 UnicodeString pattern
,Locale locale
,UErrorCode
&status
, char* errMsg
)
676 //Create the MessageFormat with simple SelectFormat
677 LocalPointer
<MessageFormat
> msgFmt(new MessageFormat(pattern
, locale
, status
));
678 if (U_FAILURE(status
)) {
679 dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
680 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status
);
683 return msgFmt
.orphan();
686 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
688 logln("running TestMessageFormat::testMsgFormatSelect");
690 UErrorCode err
= U_ZERO_ERROR
;
692 UnicodeString
t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
695 //Create the MessageFormat with simple French pattern
696 MessageFormat
* msgFmt1
= internalCreate(t1
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t1");
697 if (!U_FAILURE(err
)) {
699 Formattable testArgs10
[] = {"Kirti","female"};
700 Formattable testArgs11
[] = {"Victor","other"};
701 Formattable testArgs12
[] = {"Ash","unknown"};
702 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
703 UnicodeString exp
[] = {
704 "Kirti est all\\u00E9e \\u00E0 Paris." ,
705 "Victor est all\\u00E9 \\u00E0 Paris.",
706 "Ash est all\\u00E9 \\u00E0 Paris."};
708 for( int i
=0; i
< 3; i
++){
709 internalFormat( msgFmt1
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
714 //Quoted French Pattern
715 UnicodeString
t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
717 //Create the MessageFormat with Quoted French pattern
718 MessageFormat
* msgFmt2
= internalCreate(t2
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t2");
719 if (!U_FAILURE(err
)) {
721 Formattable testArgs10
[] = {"Kirti","female"};
722 Formattable testArgs11
[] = {"Victor","other"};
723 Formattable testArgs12
[] = {"Ash","male"};
724 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
725 UnicodeString exp
[] = {
726 "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
727 "Victor est all\\u00E9 c'est \\u00E0 Paris.",
728 "Ash est all\\u00E9 c'est \\u00E0 Paris."};
730 for( int i
=0; i
< 3; i
++){
731 internalFormat( msgFmt2
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
737 UnicodeString
t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
739 //Create the MessageFormat with English pattern
740 MessageFormat
* msgFmt3
= internalCreate(t3
, Locale("en"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t3");
741 if (!U_FAILURE(err
)) {
743 Formattable testArgs10
[] = {"female"};
744 Formattable testArgs11
[] = {"other"};
745 Formattable testArgs12
[] = {"male"};
746 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
747 UnicodeString exp
[] = {
748 "FEMALE FR company published new books." ,
749 "FR otherValue published new books.",
750 "MALE FR company published new books."};
752 for( int i
=0; i
< 3; i
++){
753 internalFormat( msgFmt3
, testArgs
[i
], 1, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
758 //Nested patterns with plural, number ,choice ,select format etc.
759 //Select Format with embedded number format
760 UnicodeString
t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
762 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
763 MessageFormat
* msgFmt4
= internalCreate(t4
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t4");
764 if (!U_FAILURE(err
)) {
766 Formattable testArgs10
[] = {"Kirti","female",(int32_t)6};
767 Formattable testArgs11
[] = {"Kirti","female",100.100};
768 Formattable testArgs12
[] = {"Kirti","other",(int32_t)6};
769 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
770 UnicodeString exp
[] = {
771 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
772 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
773 "Kirti est all\\u00E9 \\u00E0 Paris."};
775 for( int i
=0; i
< 3; i
++){
776 internalFormat( msgFmt4
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
781 //Plural format with embedded select format
782 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.");
784 //Create the MessageFormat with Plural format with embedded select format(nested pattern)
785 MessageFormat
* msgFmt5
= internalCreate(t5
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t5");
786 // with no data the above should fail but it seems to construct an invalid MessageFormat with no reported error. See #13079
787 if (!U_FAILURE(err
)) {
789 Formattable testArgs10
[] = {"Kirti",(int32_t)6,"female"};
790 Formattable testArgs11
[] = {"Kirti",(int32_t)1,"female"};
791 Formattable testArgs12
[] = {"Ash",(int32_t)1,"other"};
792 Formattable testArgs13
[] = {"Ash",(int32_t)5,"other"};
793 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
};
794 UnicodeString exp
[] = {
795 "Kirti sont all\\u00E9es \\u00E0 Paris." ,
796 "Kirti est all\\u00E9e \\u00E0 Paris.",
797 "Ash est all\\u00E9 \\u00E0 Paris.",
798 "Ash sont all\\u00E9s \\u00E0 Paris."};
800 for( int i
=0; i
< 4; i
++){
801 internalFormat( msgFmt5
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
807 //Select, plural, and number formats heavily nested
808 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.");
809 //Create the MessageFormat with Select, plural, and number formats heavily nested
810 LocalPointer
<MessageFormat
> msgFmt6(
811 internalCreate(t6
, Locale("de"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t6"));
812 if (!U_FAILURE(err
)) {
814 Formattable testArgs10
[] = {"Kirti","other",(int32_t)1,"other"};
815 Formattable testArgs11
[] = {"Kirti","other",(int32_t)6,"other"};
816 Formattable testArgs12
[] = {"Kirti","other",(int32_t)1,"female"};
817 Formattable testArgs13
[] = {"Kirti","other",(int32_t)3,"female"};
818 Formattable testArgs14
[] = {"Kirti","female",(int32_t)1,"female"};
819 Formattable testArgs15
[] = {"Kirti","female",(int32_t)5,"female"};
820 Formattable testArgs16
[] = {"Kirti","female",(int32_t)1,"other"};
821 Formattable testArgs17
[] = {"Kirti","female",(int32_t)5,"other"};
822 Formattable testArgs18
[] = {"Kirti","mixed",(int32_t)1,"mixed"};
823 Formattable testArgs19
[] = {"Kirti","mixed",(int32_t)1,"other"};
824 Formattable testArgs20
[] = {"Kirti","female",(int32_t)1,"mixed"};
825 Formattable testArgs21
[] = {"Kirti","mixed",(int32_t)5,"mixed"};
826 Formattable testArgs22
[] = {"Kirti","mixed",(int32_t)5,"other"};
827 Formattable testArgs23
[] = {"Kirti","female",(int32_t)5,"mixed"};
828 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
,
829 testArgs14
,testArgs15
,testArgs16
,testArgs17
,
830 testArgs18
,testArgs19
,testArgs20
,testArgs21
,
831 testArgs22
,testArgs23
};
832 UnicodeString exp
[] = {
833 "Kirti und sein Freund gingen nach Paris." ,
834 "Kirti und seine 6 Freunde gingen nach Paris." ,
835 "Kirti und seine Freundin gingen nach Paris.",
836 "Kirti und seine 3 Freundinnen gingen nach Paris.",
837 "Kirti und ihre Freundin gingen nach Paris.",
838 "Kirti und ihre 5 Freundinnen gingen nach Paris.",
839 "Kirti und ihr Freund gingen nach Paris.",
840 "Kirti und ihre 5 Freunde gingen nach Paris.",
841 "Kirti und sein Freund gingen nach Paris.",
842 "Kirti und sein Freund gingen nach Paris.",
843 "Kirti und ihr Freund gingen nach Paris.",
844 "Kirti und seine 5 Freunde gingen nach Paris." ,
845 "Kirti und seine 5 Freunde gingen nach Paris." ,
846 "Kirti und ihre 5 Freunde gingen nach Paris."
849 for( int i
=0; i
< 14; i
++){
850 internalFormat( msgFmt6
.getAlias(), testArgs
[i
], 4, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
855 //---------------------------------
857 //---------------------------------
859 void TestMessageFormat::testCopyConstructor()
861 UErrorCode success
= U_ZERO_ERROR
;
862 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
863 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
864 MessageFormat
*y
= 0;
865 y
= new MessageFormat(*x
);
869 logln("First test (operator ==): Passed!");
871 errln("TestMessageFormat::testCopyConstructor failed #1");
872 logln("First test (operator ==): Failed!");
874 if ( ((*x
== *y
) && (*y
== *x
)) &&
875 ((*x
!= *z
) && (*z
!= *x
)) &&
876 ((*y
!= *z
) && (*z
!= *y
)) )
877 logln("Second test (equals): Passed!");
879 errln("TestMessageFormat::testCopyConstructor failed #2");
880 logln("Second test (equals): Failed!");
889 void TestMessageFormat::testAssignment()
891 UErrorCode success
= U_ZERO_ERROR
;
892 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
893 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
894 MessageFormat
*y
= new MessageFormat("There are {0} files on {1} created", success
);
899 logln("First test (operator ==): Passed!");
901 errln( "TestMessageFormat::testAssignment failed #1");
902 logln("First test (operator ==): Failed!");
904 if ( ((*x
== *y
) && (*y
== *x
)) &&
905 ((*x
!= *z
) && (*z
!= *x
)) &&
906 ((*y
!= *z
) && (*z
!= *y
)) )
907 logln("Second test (equals): Passed!");
909 errln("TestMessageFormat::testAssignment failed #2");
910 logln("Second test (equals): Failed!");
918 void TestMessageFormat::testClone()
920 UErrorCode success
= U_ZERO_ERROR
;
921 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
922 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
923 MessageFormat
*y
= 0;
928 logln("First test (operator ==): Passed!");
930 errln("TestMessageFormat::testClone failed #1");
931 logln("First test (operator ==): Failed!");
933 if ( ((*x
== *y
) && (*y
== *x
)) &&
934 ((*x
!= *z
) && (*z
!= *x
)) &&
935 ((*y
!= *z
) && (*z
!= *y
)) )
936 logln("Second test (equals): Passed!");
938 errln("TestMessageFormat::testClone failed #2");
939 logln("Second test (equals): Failed!");
947 void TestMessageFormat::testEquals()
949 UErrorCode success
= U_ZERO_ERROR
;
950 MessageFormat
x("There are {0} files on {1}", success
);
951 MessageFormat
y("There are {0} files on {1}", success
);
953 errln( "TestMessageFormat::testEquals failed #1");
954 logln("First test (operator ==): Failed!");
959 void TestMessageFormat::testNotEquals()
961 UErrorCode success
= U_ZERO_ERROR
;
962 MessageFormat
x("There are {0} files on {1}", success
);
964 y
.setLocale(Locale("fr"));
966 errln( "TestMessageFormat::testEquals failed #1");
967 logln("First test (operator !=): Failed!");
970 y
.applyPattern("There are {0} files on {1} the disk", success
);
972 errln( "TestMessageFormat::testEquals failed #1");
973 logln("Second test (operator !=): Failed!");
978 void TestMessageFormat::testSetLocale()
980 UErrorCode err
= U_ZERO_ERROR
;
981 GregorianCalendar
cal(err
);
982 Formattable arguments
[] = {
984 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
988 UnicodeString result
;
990 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
991 UnicodeString formatStr
= "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
992 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
993 // Just use unlocalized currency symbol.
994 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
995 UnicodeString compareStrEng
= "At <time> on Aug 8, 1997, you made a deposit of ";
996 compareStrEng
+= (UChar
) 0x00a4;
997 compareStrEng
+= "456.83.";
998 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
999 // Just use unlocalized currency symbol.
1000 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
1001 UnicodeString compareStrGer
= "At <time> on 08.08.1997, you made a deposit of ";
1002 compareStrGer
+= "456,83";
1003 compareStrGer
+= (UChar
) 0x00a0;
1004 compareStrGer
+= "XXX.";
1006 MessageFormat
msg( formatStr
, err
);
1008 FieldPosition
pos(FieldPosition::DONT_CARE
);
1009 result
= msg
.format(
1017 if (result
!= compareStrEng
) {
1019 result
.extract(0, result
.length(), bbuf
, sizeof(bbuf
));
1020 dataerrln("*** MSG format err. - %s; result was %s", u_errorName(err
), bbuf
);
1023 msg
.setLocale(Locale::getEnglish());
1024 UBool getLocale_ok
= TRUE
;
1025 if (msg
.getLocale() != Locale::getEnglish()) {
1026 errln("*** MSG getLocale err.");
1027 getLocale_ok
= FALSE
;
1030 msg
.setLocale(Locale::getGerman());
1032 if (msg
.getLocale() != Locale::getGerman()) {
1033 errln("*** MSG getLocal err.");
1034 getLocale_ok
= FALSE
;
1037 msg
.applyPattern( formatStr
, err
);
1041 result
= msg
.format(
1049 if (result
== compareStrGer
) {
1050 logln("MSG setLocale tested.");
1052 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err
));
1056 logln("MSG getLocale tested.");
1060 void TestMessageFormat::testFormat()
1062 UErrorCode err
= U_ZERO_ERROR
;
1063 GregorianCalendar
cal(err
);
1065 const Formattable ftarray
[] =
1067 Formattable( UDate(8.71068e+011), Formattable::kIsDate
)
1069 const int32_t ft_cnt
= UPRV_LENGTHOF(ftarray
);
1070 Formattable
ft_arr( ftarray
, ft_cnt
);
1072 Formattable
* fmt
= new Formattable(UDate(8.71068e+011), Formattable::kIsDate
);
1074 UnicodeString result
;
1076 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
1077 UnicodeString formatStr
= "On {0,date}, it began.";
1078 UnicodeString compareStr
= "On Aug 8, 1997, it began.";
1081 MessageFormat
msg( formatStr
, err
);
1082 FieldPosition
fp(FieldPosition::DONT_CARE
);
1086 result
= msg
.format(
1089 //FieldPosition(FieldPosition::DONT_CARE),
1093 if (err
!= U_ILLEGAL_ARGUMENT_ERROR
) {
1094 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err
));
1100 result
= msg
.format(
1103 //FieldPosition(FieldPosition::DONT_CARE),
1107 logln("MSG format( Formattable&, ... ) expected:" + compareStr
);
1108 logln("MSG format( Formattable&, ... ) result:" + result
);
1109 if (result
!= compareStr
) {
1110 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err
));
1112 logln("MSG format( Formattable&, ... ) tested.");
1119 void TestMessageFormat::testParse()
1121 UErrorCode err
= U_ZERO_ERROR
;
1123 UnicodeString msgFormatString
= "{0} =sep= {1}";
1124 MessageFormat
msg( msgFormatString
, err
);
1125 UnicodeString source
= "abc =sep= def";
1126 UnicodeString tmp1
, tmp2
;
1128 Formattable
* fmt_arr
= msg
.parse( source
, count
, err
);
1129 if (U_FAILURE(err
) || (!fmt_arr
)) {
1130 errln("*** MSG parse (ustring, count, err) error.");
1132 logln("MSG parse -- count: %d", count
);
1134 errln("*** MSG parse (ustring, count, err) count err.");
1136 if ((fmt_arr
[0].getType() == Formattable::kString
)
1137 && (fmt_arr
[1].getType() == Formattable::kString
)
1138 && (fmt_arr
[0].getString(tmp1
) == "abc")
1139 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1140 logln("MSG parse (ustring, count, err) tested.");
1142 errln("*** MSG parse (ustring, count, err) result err.");
1148 ParsePosition
pp(0);
1150 fmt_arr
= msg
.parse( source
, pp
, count
);
1151 if ((pp
== 0) || (!fmt_arr
)) {
1152 errln("*** MSG parse (ustring, parsepos., count) error.");
1154 logln("MSG parse -- count: %d", count
);
1156 errln("*** MSG parse (ustring, parsepos., count) count err.");
1158 if ((fmt_arr
[0].getType() == Formattable::kString
)
1159 && (fmt_arr
[1].getType() == Formattable::kString
)
1160 && (fmt_arr
[0].getString(tmp1
) == "abc")
1161 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1162 logln("MSG parse (ustring, parsepos., count) tested.");
1164 errln("*** MSG parse (ustring, parsepos., count) result err.");
1173 msg
.parseObject( source
, fmta
, pp
);
1175 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1177 logln("MSG parse -- count: %d", count
);
1178 fmta
.getArray(count
);
1180 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1182 if ((fmta
[0].getType() == Formattable::kString
)
1183 && (fmta
[1].getType() == Formattable::kString
)
1184 && (fmta
[0].getString(tmp1
) == "abc")
1185 && (fmta
[1].getString(tmp2
) == "def")) {
1186 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
1188 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1195 void TestMessageFormat::testAdopt()
1197 UErrorCode err
= U_ZERO_ERROR
;
1199 UnicodeString
formatStr("{0,date},{1},{2,number}", "");
1200 UnicodeString
formatStrChange("{0,number},{1,number},{2,date}", "");
1202 MessageFormat
msg( formatStr
, err
);
1203 MessageFormat
msgCmp( formatStr
, err
);
1204 if (U_FAILURE(err
)) {
1205 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err
));
1208 int32_t count
, countCmp
;
1209 const Format
** formats
= msg
.getFormats(count
);
1210 const Format
** formatsCmp
= msgCmp
.getFormats(countCmp
);
1211 const Format
** formatsChg
= 0;
1212 const Format
** formatsAct
= 0;
1216 UnicodeString patCmp
;
1217 UnicodeString patAct
;
1218 Format
** formatsToAdopt
;
1220 if (!formats
|| !formatsCmp
|| (count
<= 0) || (count
!= countCmp
)) {
1221 dataerrln("Error getting Formats");
1227 for (i
= 0; i
< count
; i
++) {
1230 if ((a
!= NULL
) && (b
!= NULL
)) {
1235 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1236 errln("(a != NULL) || (b != NULL)");
1241 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1243 formatsChg
= msg
.getFormats(countChg
); // tested function
1244 if (!formatsChg
|| (countChg
!= count
)) {
1245 errln("Error getting Formats");
1251 for (i
= 0; i
< count
; i
++) {
1254 if ((a
!= NULL
) && (b
!= NULL
)) {
1256 logln("formatsChg == formatsCmp at index %d", i
);
1262 errln("*** MSG getFormats diff err.");
1266 logln("MSG getFormats tested.");
1268 msg
.setFormats( formatsCmp
, countCmp
); //tested function
1270 formatsAct
= msg
.getFormats(countAct
);
1271 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1272 errln("Error getting Formats");
1276 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1277 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1278 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1279 msg
.toPattern(patCmp
.remove());
1280 if (!patCmp
.isBogus()) {
1281 errln("msg.setFormat().toPattern() succeeds.");
1284 for (i
= 0; i
< countAct
; i
++) {
1287 if ((a
!= NULL
) && (b
!= NULL
)) {
1289 logln("formatsAct != formatsCmp at index %d", i
);
1293 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1294 errln("(a != NULL) || (b != NULL)");
1298 logln("MSG setFormats tested.");
1302 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1304 formatsToAdopt
= new Format
* [countCmp
];
1305 if (!formatsToAdopt
) {
1306 errln("memory allocation error");
1310 for (i
= 0; i
< countCmp
; i
++) {
1311 if (formatsCmp
[i
] == NULL
) {
1312 formatsToAdopt
[i
] = NULL
;
1314 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1315 if (!formatsToAdopt
[i
]) {
1316 errln("Can't clone format at index %d", i
);
1321 msg
.adoptFormats( formatsToAdopt
, countCmp
); // function to test
1322 delete[] formatsToAdopt
;
1324 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1325 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1326 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1328 formatsAct
= msg
.getFormats(countAct
);
1329 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1330 errln("Error getting Formats");
1334 for (i
= 0; i
< countAct
; i
++) {
1337 if ((a
!= NULL
) && (b
!= NULL
)) {
1342 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1343 errln("(a != NULL) || (b != NULL)");
1347 logln("MSG adoptFormats tested.");
1351 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1353 formatsToAdopt
= new Format
* [countCmp
];
1354 if (!formatsToAdopt
) {
1355 errln("memory allocation error");
1359 for (i
= 0; i
< countCmp
; i
++) {
1360 if (formatsCmp
[i
] == NULL
) {
1361 formatsToAdopt
[i
] = NULL
;
1363 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1364 if (!formatsToAdopt
[i
]) {
1365 errln("Can't clone format at index %d", i
);
1371 for ( i
= 0; i
< countCmp
; i
++ ) {
1372 msg
.adoptFormat( i
, formatsToAdopt
[i
] ); // function to test
1374 delete[] formatsToAdopt
; // array itself not needed in this case;
1376 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1377 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1378 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1380 formatsAct
= msg
.getFormats(countAct
);
1381 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1382 errln("Error getting Formats");
1386 for (i
= 0; i
< countAct
; i
++) {
1389 if ((a
!= NULL
) && (b
!= NULL
)) {
1394 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1395 errln("(a != NULL) || (b != NULL)");
1399 logln("MSG adoptFormat tested.");
1402 // This test is a regression test for a fixed bug in the copy constructor.
1403 // It is kept as a global function rather than as a method since the test depends on memory values.
1404 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1405 // which is probably why it didn't show up in the regular test for the copy constructor.)
1406 // For this reason, the test isn't changed even though it contains function calls whose results are
1407 // not tested and had no problems. Actually, the test failed by *crashing*.
1408 static void _testCopyConstructor2()
1410 UErrorCode status
= U_ZERO_ERROR
;
1411 UnicodeString
formatStr("Hello World on {0,date,full}", "");
1412 UnicodeString
resultStr(" ", "");
1413 UnicodeString result
;
1414 FieldPosition
fp(FieldPosition::DONT_CARE
);
1415 UDate d
= Calendar::getNow();
1416 const Formattable
fargs( d
, Formattable::kIsDate
);
1418 MessageFormat
* fmt1
= new MessageFormat( formatStr
, status
);
1419 MessageFormat
* fmt2
= NULL
;
1420 MessageFormat
* fmt3
= NULL
;
1421 MessageFormat
* fmt4
= NULL
;
1424 it_err("testCopyConstructor2: (fmt1 != NULL)");
1428 fmt2
= new MessageFormat( *fmt1
);
1429 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1432 it_err("testCopyConstructor2: (fmt2 != NULL)");
1436 fmt3
= fmt1
->clone();
1437 fmt4
= fmt2
->clone();
1440 it_err("testCopyConstructor2: (fmt3 != NULL)");
1444 it_err("testCopyConstructor2: (fmt4 != NULL)");
1448 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1449 result
= fmt2
->format( &fargs
, 1, resultStr
, fp
, status
);
1450 result
= fmt3
->format( &fargs
, 1, resultStr
, fp
, status
);
1451 result
= fmt4
->format( &fargs
, 1, resultStr
, fp
, status
);
1460 void TestMessageFormat::testCopyConstructor2() {
1461 _testCopyConstructor2();
1465 * Verify that MessageFormat accomodates more than 10 arguments and
1466 * more than 10 subformats.
1468 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1469 UErrorCode ec
= U_ZERO_ERROR
;
1470 const UnicodeString pattern
=
1471 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1472 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1473 "there were {1,number} werjes "
1474 "(a {3,number,percent} increase over {2,number}) "
1475 "despite the {4}''s efforts "
1476 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1477 MessageFormat
msg(pattern
, ec
);
1478 if (U_FAILURE(ec
)) {
1479 dataerrln("FAIL: constructor failed - %s", u_errorName(ec
));
1483 const Formattable ARGS
[] = {
1484 Formattable(UDate(1e13
), Formattable::kIsDate
),
1485 Formattable((int32_t)1303),
1486 Formattable((int32_t)1202),
1487 Formattable(1303.0/1202 - 1),
1488 Formattable("Glimmung"),
1489 Formattable("the printers"),
1490 Formattable("Nick"),
1491 Formattable("his father"),
1492 Formattable("his mother"),
1493 Formattable("the spiddles"),
1494 Formattable("of course"),
1495 Formattable("Horace"),
1497 const int32_t ARGS_LENGTH
= UPRV_LENGTHOF(ARGS
);
1498 Formattable
ARGS_OBJ(ARGS
, ARGS_LENGTH
);
1500 UnicodeString expected
=
1501 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1502 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1503 "there were 1,303 werjes "
1504 "(a 8% increase over 1,202) "
1505 "despite the Glimmung's efforts "
1506 "and to delight of the printers, Nick, his father, "
1507 "his mother, the spiddles, and of course Horace.";
1508 UnicodeString result
;
1509 msg
.format(ARGS_OBJ
, result
, ec
);
1510 if (result
== expected
) {
1513 errln((UnicodeString
)"FAIL: Got " + result
+
1514 ", expected " + expected
);
1518 // test RBNF extensions to message format
1519 void TestMessageFormat::TestRBNF(void) {
1520 // WARNING: this depends on the RBNF formats for en_US
1521 Locale
locale("en", "US", "");
1523 UErrorCode ec
= U_ZERO_ERROR
;
1525 UnicodeString values
[] = {
1526 // decimal values do not format completely for ordinal or duration, and
1527 // do not always parse, so do not include them
1528 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1530 int32_t values_count
= UPRV_LENGTHOF(values
);
1532 UnicodeString formats
[] = {
1533 "There are {0,spellout} files to search.",
1534 "There are {0,spellout,%simplified} files to search.",
1535 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1536 "This is the {0,ordinal} file to search.",
1537 "Searching this file will take {0,duration} to complete.",
1538 "Searching this file will take {0,duration,%with-words} to complete.",
1540 int32_t formats_count
= UPRV_LENGTHOF(formats
);
1542 Formattable args
[1];
1544 NumberFormat
* numFmt
= NumberFormat::createInstance(locale
, ec
);
1545 if (U_FAILURE(ec
)) {
1546 dataerrln("Error calling NumberFormat::createInstance()");
1550 for (int i
= 0; i
< formats_count
; ++i
) {
1551 MessageFormat
* fmt
= new MessageFormat(formats
[i
], locale
, ec
);
1552 logln((UnicodeString
)"Testing format pattern: '" + formats
[i
] + "'");
1554 for (int j
= 0; j
< values_count
; ++j
) {
1556 numFmt
->parse(values
[j
], args
[0], ec
);
1557 if (U_FAILURE(ec
)) {
1558 errln((UnicodeString
)"Failed to parse test argument " + values
[j
]);
1560 FieldPosition
fp(FieldPosition::DONT_CARE
);
1561 UnicodeString result
;
1562 fmt
->format(args
, 1, result
, fp
, ec
);
1563 logln((UnicodeString
)"value: " + toString(args
[0]) + " --> " + result
+ UnicodeString(" ec: ") + u_errorName(ec
));
1566 Formattable
* parseResult
= fmt
->parse(result
, count
, ec
);
1568 errln((UnicodeString
)"parse returned " + count
+ " args");
1569 } else if (parseResult
[0] != args
[0]) {
1570 errln((UnicodeString
)"parsed argument " + toString(parseResult
[0]) + " != " + toString(args
[0]));
1572 delete []parseResult
;
1580 UnicodeString
TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern
& pattern
) {
1581 UnicodeString
us(pattern
.getPatternString());
1582 int count
= pattern
.countParts();
1583 for (int i
= count
; i
> 0;) {
1584 const MessagePattern::Part
& part
= pattern
.getPart(--i
);
1585 if (part
.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX
) {
1586 us
.remove(part
.getIndex(), part
.getLimit() - part
.getIndex());
1592 void TestMessageFormat::TestApostropheMode() {
1593 UErrorCode status
= U_ZERO_ERROR
;
1594 MessagePattern
*ado_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL
, status
);
1595 MessagePattern
*adr_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED
, status
);
1596 if (ado_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1597 errln("wrong value from ado_mp->getApostropheMode().");
1599 if (adr_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1600 errln("wrong value from adr_mp->getApostropheMode().");
1604 UnicodeString tuples
[] = {
1606 // DOUBLE_OPTIONAL pattern
1607 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1608 "I see {many}", "I see '{many}'", "",
1609 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1610 "I dont know", "I dont know", "I don't know",
1611 "I don't know", "I don't know", "I don''t know",
1612 "I don't know", "I don''t know", "I don''t know"
1614 int32_t tuples_count
= UPRV_LENGTHOF(tuples
);
1616 for (int i
= 0; i
< tuples_count
; i
+= 3) {
1617 UnicodeString
& desired
= tuples
[i
];
1618 UnicodeString
& ado_pattern
= tuples
[i
+ 1];
1619 UErrorCode status
= U_ZERO_ERROR
;
1620 assertEquals("DOUBLE_OPTIONAL failure",
1622 GetPatternAndSkipSyntax(ado_mp
->parse(ado_pattern
, NULL
, status
)));
1623 UnicodeString
& adr_pattern
= tuples
[i
+ 2].isEmpty() ? ado_pattern
: tuples
[i
+ 2];
1624 assertEquals("DOUBLE_REQUIRED failure", desired
,
1625 GetPatternAndSkipSyntax(adr_mp
->parse(adr_pattern
, NULL
, status
)));
1632 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
1633 void TestMessageFormat::TestCompatibleApostrophe() {
1634 // Message with choice argument which does not contain another argument.
1635 // The JDK performs only one apostrophe-quoting pass on this pattern.
1636 UnicodeString pattern
= "ab{0,choice,0#1'2''3'''4''''.}yz";
1638 UErrorCode ec
= U_ZERO_ERROR
;
1639 MessageFormat
compMsg("", Locale::getUS(), ec
);
1640 compMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_REQUIRED
, NULL
, ec
);
1641 if (compMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1642 errln("wrong value from compMsg.getApostropheMode().");
1645 MessageFormat
icuMsg("", Locale::getUS(), ec
);
1646 icuMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_OPTIONAL
, NULL
, ec
);
1647 if (icuMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1648 errln("wrong value from icuMsg.getApostropheMode().");
1651 Formattable zero0
[] = { (int32_t)0 };
1652 FieldPosition
fieldpos(FieldPosition::DONT_CARE
);
1653 UnicodeString buffer1
, buffer2
;
1654 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1656 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1657 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1659 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1661 // Message with choice argument which contains a nested simple argument.
1662 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1665 pattern
= "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1666 compMsg
.applyPattern(pattern
, ec
);
1667 icuMsg
.applyPattern(pattern
, ec
);
1668 if (U_FAILURE(ec
)) {
1669 dataerrln("Unable to applyPattern - %s", u_errorName(ec
));
1671 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1673 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1674 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1675 "ab1'2'3''4''.#x0yz",
1676 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1679 // This part is copied over from Java tests but cannot be properly tested here
1680 // because we do not have a live reference implementation with JDK behavior.
1681 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1683 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1684 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1687 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1688 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1689 "12'3'4''.{0,number,#x}",
1694 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1695 const char* patterns
[] = { // pattern, expected pattern
1706 "{'a{}'a}'a", "{'a{}'a}''a",
1708 "'} '{'}'", "'} '{'}''",
1709 "'} {{{''", "'} {{{'''",
1711 int32_t pattern_count
= UPRV_LENGTHOF(patterns
);
1713 for (int i
= 0; i
< pattern_count
; i
+= 2) {
1714 UErrorCode status
= U_ZERO_ERROR
;
1715 UnicodeString result
= MessageFormat::autoQuoteApostrophe(patterns
[i
], status
);
1716 UnicodeString
target(patterns
[i
+1]);
1717 if (target
!= result
) {
1718 const int BUF2_LEN
= 64;
1720 char buf2
[BUF2_LEN
];
1721 int32_t len
= result
.extract(0, result
.length(), buf2
, BUF2_LEN
);
1722 if (len
>= BUF2_LEN
) {
1723 buf2
[BUF2_LEN
-1] = 0;
1725 sprintf(buf
, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i
/2, patterns
[i
], patterns
[i
+1], buf2
);
1731 void TestMessageFormat::testCoverage(void) {
1732 UErrorCode status
= U_ZERO_ERROR
;
1733 UnicodeString
testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1734 MessageFormat
*msgfmt
= new MessageFormat(testformat
, Locale("fr"), status
);
1735 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1736 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status
));
1739 if (!msgfmt
->usesNamedArguments()) {
1740 errln("FAIL: Unable to detect usage of named arguments.");
1742 const double limit
[] = {0.0, 1.0, 2.0};
1743 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
1746 ChoiceFormat
cf(limit
, formats
, 3);
1748 msgfmt
->setFormat("set", cf
, status
);
1750 StringEnumeration
*en
= msgfmt
->getFormatNames(status
);
1751 if (en
== NULL
|| U_FAILURE(status
)) {
1752 errln("FAIL: Unable to get format names enumeration.");
1756 count
= en
->count(status
);
1757 if (U_FAILURE(status
)) {
1758 errln("FAIL: Unable to get format name enumeration count.");
1760 for (int32_t i
= 0; i
< count
; i
++) {
1762 if (U_FAILURE(status
)) {
1763 errln("FAIL: Error enumerating through names.");
1770 // adoptFormat() takes ownership of the input Format object.
1771 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1772 Format
*cfClone
= cf
.clone();
1773 msgfmt
->adoptFormat("adopt", cfClone
, status
);
1778 msgfmt
= new MessageFormat("'", status
);
1779 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1780 errln("FAIL: Unable to create MessageFormat.");
1783 if (msgfmt
->usesNamedArguments()) {
1784 errln("FAIL: Unable to detect usage of named arguments.");
1787 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1788 // on a MessageFormat without named arguments.
1789 msgfmt
->setFormat("formatName", cf
, status
);
1790 if (U_FAILURE(status
)) {
1791 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1793 status
= U_ZERO_ERROR
;
1794 en
= msgfmt
->getFormatNames(status
);
1795 if (U_FAILURE(status
)) {
1796 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1803 void TestMessageFormat::testGetFormatNames() {
1804 IcuTestErrorCode
errorCode(*this, "testGetFormatNames");
1805 MessageFormat
msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode
);
1806 if(errorCode
.errDataIfFailureAndReset("MessageFormat() failed")) {
1809 LocalPointer
<StringEnumeration
> names(msgfmt
.getFormatNames(errorCode
));
1810 if(errorCode
.errIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1813 const UnicodeString
*name
;
1814 name
= names
->snext(errorCode
);
1815 if (name
== NULL
|| errorCode
.isFailure()) {
1816 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode
.errorName());
1820 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name
)) {
1823 name
= names
->snext(errorCode
);
1824 if (name
== NULL
|| errorCode
.isFailure()) {
1825 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode
.errorName());
1829 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name
)) {
1832 name
= names
->snext(errorCode
);
1833 if (name
== NULL
|| errorCode
.isFailure()) {
1834 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode
.errorName());
1838 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name
)) {
1841 name
= names
->snext(errorCode
);
1843 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name
);
1848 void TestMessageFormat::TestTrimArgumentName() {
1849 // ICU 4.8 allows and ignores white space around argument names and numbers.
1850 IcuTestErrorCode
errorCode(*this, "TestTrimArgumentName");
1851 MessageFormat
m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode
);
1852 if (errorCode
.errDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1855 Formattable args
[1] = { (int32_t)2 };
1856 FieldPosition
ignore(FieldPosition::DONT_CARE
);
1857 UnicodeString result
;
1858 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1859 m
.format(args
, 1, result
, ignore
, errorCode
));
1861 m
.applyPattern("x { _oOo_ , number , integer } y", errorCode
);
1862 UnicodeString argName
= UNICODE_STRING_SIMPLE("_oOo_");
1865 assertEquals("trim-named-arg format() failed", "x 3 y",
1866 m
.format(&argName
, args
, 1, result
, errorCode
));
1869 void TestMessageFormat::TestSelectOrdinal() {
1870 IcuTestErrorCode
errorCode(*this, "TestSelectOrdinal");
1871 // Test plural & ordinal together,
1872 // to make sure that we get the correct cached PluralSelector for each.
1874 "{0,plural,one{1 file}other{# files}}, "
1875 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
1876 Locale::getEnglish(), errorCode
);
1877 if (errorCode
.errDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1880 Formattable args
[1] = { (int32_t)21 };
1881 FieldPosition
ignore(FieldPosition::DONT_CARE
);
1882 UnicodeString result
;
1883 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file",
1884 m
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1887 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1888 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1891 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1892 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1895 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1896 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1898 errorCode
.errDataIfFailureAndReset("");
1901 void TestMessageFormat::TestDecimals() {
1902 IcuTestErrorCode
errorCode(*this, "TestDecimals");
1903 // Simple number replacement.
1905 "{0,plural,one{one meter}other{# meters}}",
1906 Locale::getEnglish(), errorCode
);
1907 Formattable args
[1] = { (int32_t)1 };
1908 FieldPosition ignore
;
1909 UnicodeString result
;
1910 assertEquals("simple format(1)", "one meter",
1911 m
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1913 args
[0] = (double)1.5;
1915 assertEquals("simple format(1.5)", "1.5 meters",
1916 m
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1918 // Simple but explicit.
1920 "{0,plural,one{one meter}other{{0} meters}}",
1921 Locale::getEnglish(), errorCode
);
1922 args
[0] = (int32_t)1;
1924 assertEquals("explicit format(1)", "one meter",
1925 m0
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1927 args
[0] = (double)1.5;
1929 assertEquals("explicit format(1.5)", "1.5 meters",
1930 m0
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1932 // With offset and specific simple format with optional decimals.
1934 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1935 Locale::getEnglish(), errorCode
);
1936 args
[0] = (int32_t)1;
1938 assertEquals("offset format(1)", "01 meters",
1939 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1941 args
[0] = (int32_t)2;
1943 assertEquals("offset format(1)", "another meter",
1944 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1946 args
[0] = (double)2.5;
1948 assertEquals("offset format(1)", "02.5 meters",
1949 m1
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1951 // With offset and specific simple format with forced decimals.
1953 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1954 Locale::getEnglish(), errorCode
);
1955 args
[0] = (int32_t)1;
1957 assertEquals("offset-decimals format(1)", "1.0 meters",
1958 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1960 args
[0] = (int32_t)2;
1962 assertEquals("offset-decimals format(1)", "2.0 meters",
1963 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1965 args
[0] = (double)2.5;
1967 assertEquals("offset-decimals format(1)", "2.5 meters",
1968 m2
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1972 void TestMessageFormat::TestArgIsPrefixOfAnother() {
1973 IcuTestErrorCode
errorCode(*this, "TestArgIsPrefixOfAnother");
1975 MessageFormat
mf1("{0,select,a{A}ab{AB}abc{ABC}other{?}}", Locale::getEnglish(), errorCode
);
1976 Formattable args
[3];
1977 FieldPosition ignore
;
1978 UnicodeString result
;
1979 args
[0].setString("a");
1980 assertEquals("a", "A", mf1
.format(args
, 1, result
, ignore
, errorCode
));
1981 args
[0].setString("ab");
1982 assertEquals("ab", "AB", mf1
.format(args
, 1, result
.remove(), ignore
, errorCode
));
1983 args
[0].setString("abc");
1984 assertEquals("abc", "ABC", mf1
.format(args
, 1, result
.remove(), ignore
, errorCode
));
1987 MessageFormat
mf2("{a} {aa} {aaa}", Locale::getEnglish(), errorCode
);
1988 UnicodeString argNames
[3] = { "a", "aa", "aaa" };
1989 args
[0].setString("A");
1990 args
[1].setString("AB");
1991 args
[2].setString("ABC");
1992 assertEquals("a aa aaa", "A AB ABC", mf2
.format(argNames
, args
, 3, result
.remove(), errorCode
));
1995 MessageFormat
mf3("{aa} {aaa}", Locale::getEnglish(), errorCode
);
1996 assertEquals("aa aaa", "AB ABC", mf3
.format(argNames
+ 1, args
+ 1, 2, result
.remove(), errorCode
));
1999 void TestMessageFormat::TestMessageFormatNumberSkeleton() {
2000 IcuTestErrorCode
status(*this, "TestMessageFormatNumberSkeleton");
2002 static const struct TestCase
{
2003 const char16_t* messagePattern
;
2004 const char* localeName
;
2006 const char16_t* expected
;
2008 { u
"{0,number,::percent}", "en", 50, u
"50%" },
2009 { u
"{0,number,::percent scale/100}", "en", 0.5, u
"50%" },
2010 { u
"{0,number, :: percent scale/100 }", "en", 0.5, u
"50%" },
2011 { u
"{0,number,::currency/USD}", "en", 23, u
"$23.00" },
2012 { u
"{0,number,::precision-integer}", "en", 514.23, u
"514" },
2013 { u
"{0,number,::.000}", "en", 514.23, u
"514.230" },
2014 { u
"{0,number,::.}", "en", 514.23, u
"514" },
2015 { u
"{0,number,::}", "fr", 514.23, u
"514,23" },
2016 { u
"Cost: {0,number,::currency/EUR}.", "en", 4.3, u
"Cost: €4.30." },
2017 { u
"{0,number,'::'0.00}", "en", 50, u
"::50.00" }, // pattern literal
2020 for (auto& cas
: cases
) {
2021 status
.setScope(cas
.messagePattern
);
2022 MessageFormat
msgf(cas
.messagePattern
, cas
.localeName
, status
);
2024 FieldPosition
fpos(FieldPosition::DONT_CARE
);
2025 Formattable argsArray
[] = {{cas
.arg
}};
2026 Formattable
args(argsArray
, 1);
2027 msgf
.format(args
, sb
, status
);
2029 assertEquals(cas
.messagePattern
, cas
.expected
, sb
);
2033 void TestMessageFormat::doTheRealDateTimeSkeletonTesting(UDate testDate
,
2034 const char16_t* messagePattern
, const char* localeName
, const char16_t* expected
,
2035 IcuTestErrorCode
& status
) {
2037 status
.setScope(messagePattern
);
2038 MessageFormat
msgf(messagePattern
, localeName
, status
);
2040 FieldPosition
fpos(FieldPosition::DONT_CARE
);
2041 Formattable argsArray
[] = { Formattable(testDate
, Formattable::kIsDate
) };
2042 Formattable
args(argsArray
, 1);
2043 msgf
.format(args
, sb
, status
);
2045 assertEquals(messagePattern
, expected
, sb
);
2048 void TestMessageFormat::TestMessageFormatDateSkeleton() {
2049 IcuTestErrorCode
status(*this, "TestMessageFormatDateSkeleton");
2051 UDate date
= LocaleTest::date(2021-1900, UCAL_NOVEMBER
, 23, 16, 42, 55);
2053 doTheRealDateTimeSkeletonTesting(date
, u
"{0,date,::MMMMd}", "en", u
"November 23", status
);
2054 doTheRealDateTimeSkeletonTesting(date
, u
"{0,date,::yMMMMdjm}", "en", u
"November 23, 2021, 4:42 PM", status
);
2055 doTheRealDateTimeSkeletonTesting(date
, u
"{0,date, :: yMMMMd }", "en", u
"November 23, 2021", status
);
2056 doTheRealDateTimeSkeletonTesting(date
, u
"{0,date,::yMMMMd}", "fr", u
"23 novembre 2021", status
);
2057 doTheRealDateTimeSkeletonTesting(date
, u
"Expiration: {0,date,::yMMM}!", "en", u
"Expiration: Nov 2021!", status
);
2059 doTheRealDateTimeSkeletonTesting(date
, u
"{0,date,'::'yMMMMd}", "en", u
"::2021November23", status
);
2062 void TestMessageFormat::TestMessageFormatTimeSkeleton() {
2063 IcuTestErrorCode
status(*this, "TestMessageFormatTimeSkeleton");
2065 UDate date
= LocaleTest::date(2021-1900, UCAL_NOVEMBER
, 23, 16, 42, 55);
2067 doTheRealDateTimeSkeletonTesting(date
, u
"{0,time,::MMMMd}", "en", u
"November 23", status
);
2068 doTheRealDateTimeSkeletonTesting(date
, u
"{0,time,::yMMMMdjm}", "en", u
"November 23, 2021, 4:42 PM", status
);
2069 doTheRealDateTimeSkeletonTesting(date
, u
"{0,time, :: yMMMMd }", "en", u
"November 23, 2021", status
);
2070 doTheRealDateTimeSkeletonTesting(date
, u
"{0,time,::yMMMMd}", "fr", u
"23 novembre 2021", status
);
2071 doTheRealDateTimeSkeletonTesting(date
, u
"Expiration: {0,time,::yMMM}!", "en", u
"Expiration: Nov 2021!", status
);
2073 doTheRealDateTimeSkeletonTesting(date
, u
"{0,time,'::'yMMMMd}", "en", u
"::2021November23", status
);
2076 #endif /* #if !UCONFIG_NO_FORMATTING */