1 /********************************************************************
3 * Copyright (c) 1997-2011, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************
8 * Modification History:
10 * Date Name Description
11 * 03/24/97 helena Converted from Java.
12 * 07/11/97 helena Updated to work on AIX.
13 * 08/04/97 jfitz Updated to intltest
14 *******************************************************************/
16 #include "unicode/utypes.h"
18 #if !UCONFIG_NO_FORMATTING
22 #include "unicode/format.h"
23 #include "unicode/decimfmt.h"
24 #include "unicode/locid.h"
25 #include "unicode/msgfmt.h"
26 #include "unicode/numfmt.h"
27 #include "unicode/choicfmt.h"
28 #include "unicode/messagepattern.h"
29 #include "unicode/selfmt.h"
30 #include "unicode/gregocal.h"
33 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
36 TestMessageFormat::runIndexedTest(int32_t index
, UBool exec
,
37 const char* &name
, char* /*par*/) {
39 TESTCASE_AUTO(testBug1
);
40 TESTCASE_AUTO(testBug2
);
41 TESTCASE_AUTO(sample
);
42 TESTCASE_AUTO(PatternTest
);
43 TESTCASE_AUTO(testStaticFormat
);
44 TESTCASE_AUTO(testSimpleFormat
);
45 TESTCASE_AUTO(testMsgFormatChoice
);
46 TESTCASE_AUTO(testCopyConstructor
);
47 TESTCASE_AUTO(testAssignment
);
48 TESTCASE_AUTO(testClone
);
49 TESTCASE_AUTO(testEquals
);
50 TESTCASE_AUTO(testNotEquals
);
51 TESTCASE_AUTO(testSetLocale
);
52 TESTCASE_AUTO(testFormat
);
53 TESTCASE_AUTO(testParse
);
54 TESTCASE_AUTO(testAdopt
);
55 TESTCASE_AUTO(testCopyConstructor2
);
56 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats
);
57 TESTCASE_AUTO(TestRBNF
);
58 TESTCASE_AUTO(TestTurkishCasing
);
59 TESTCASE_AUTO(testAutoQuoteApostrophe
);
60 TESTCASE_AUTO(testMsgFormatPlural
);
61 TESTCASE_AUTO(testMsgFormatSelect
);
62 TESTCASE_AUTO(testApostropheInPluralAndSelect
);
63 TESTCASE_AUTO(TestApostropheMode
);
64 TESTCASE_AUTO(TestCompatibleApostrophe
);
65 TESTCASE_AUTO(testCoverage
);
66 TESTCASE_AUTO(TestTrimArgumentName
);
70 void TestMessageFormat::testBug3()
72 double myNumber
= -123456;
73 DecimalFormat
*form
= 0;
82 Locale("de", "AT", ""),
83 Locale("de", "CH", ""),
84 Locale("el", "", ""), // 10
85 Locale("en", "CA", ""),
86 Locale("en", "GB", ""),
87 Locale("en", "IE", ""),
88 Locale("en", "US", ""),
93 Locale("fr", "BE", ""),
94 Locale("fr", "CA", ""), // 20
95 Locale("fr", "CH", ""),
100 Locale("it", "", ""),
101 Locale("it", "CH", ""),
102 Locale("ja", "", ""),
103 Locale("ko", "", ""),
104 Locale("lt", "", ""), // 30
105 Locale("lv", "", ""),
106 Locale("mk", "", ""),
107 Locale("nl", "", ""),
108 Locale("nl", "BE", ""),
109 Locale("no", "", ""),
110 Locale("pl", "", ""),
111 Locale("pt", "", ""),
112 Locale("ro", "", ""),
113 Locale("ru", "", ""),
114 Locale("sh", "", ""), // 40
115 Locale("sk", "", ""),
116 Locale("sl", "", ""),
117 Locale("sq", "", ""),
118 Locale("sr", "", ""),
119 Locale("sv", "", ""),
120 Locale("tr", "", ""),
121 Locale("uk", "", ""),
122 Locale("zh", "", ""),
123 Locale("zh", "TW", "") // 49
126 for (i
= 0; i
< 49; i
++) {
127 UnicodeString buffer
;
128 logln(locale
[i
].getDisplayName(buffer
));
129 UErrorCode success
= U_ZERO_ERROR
;
130 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
131 form
= (DecimalFormat
*)NumberFormat::createInstance(locale
[i
], success
);
132 if (U_FAILURE(success
)) {
133 errln("Err: Number Format ");
134 logln("Number format creation failed.");
138 FieldPosition
pos(0);
140 form
->format(myNumber
, buffer
, pos
);
141 success
= U_ZERO_ERROR
;
142 ParsePosition parsePos
;
143 form
->parse(buffer
, result
, parsePos
);
144 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result
) + UnicodeString("[supposed output for result]"));
145 if (U_FAILURE(success
)) {
146 errln("Err: Number Format parse");
147 logln("Number format parse failed.");
153 void TestMessageFormat::testBug1()
155 const double limit
[] = {0.0, 1.0, 2.0};
156 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
159 ChoiceFormat
*cf
= new ChoiceFormat(limit
, formats
, 3);
160 FieldPosition
status(0);
161 UnicodeString toAppendTo
;
162 cf
->format((int32_t)1, toAppendTo
, status
);
163 if (toAppendTo
!= "1.0<=Arg<2.0") {
164 errln("ChoiceFormat cmp in testBug1");
170 void TestMessageFormat::testBug2()
172 UErrorCode status
= U_ZERO_ERROR
;
173 UnicodeString result
;
174 // {sfb} use double format in pattern, so result will match (not strictly necessary)
175 const UnicodeString pattern
= "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
176 logln("The input pattern : " + pattern
);
177 MessageFormat
*fmt
= new MessageFormat(pattern
, status
);
178 if (U_FAILURE(status
)) {
179 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status
));
182 logln("The output pattern is : " + fmt
->toPattern(result
));
183 if (pattern
!= result
) {
184 errln("MessageFormat::toPattern() failed.");
190 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
191 //----------------------------------------------------
193 //----------------------------------------------------
196 std::ostream
& operator<<(std::ostream
& stream
, const Formattable
& obj
);
198 #include "unicode/datefmt.h"
203 operator<<( IntlTest
& stream
,
204 const Formattable
& obj
)
206 static DateFormat
*defDateFormat
= 0;
208 UnicodeString buffer
;
209 switch(obj
.getType()) {
210 case Formattable::kDate
:
211 if (defDateFormat
== 0) {
212 defDateFormat
= DateFormat::createInstance();
214 defDateFormat
->format(obj
.getDate(), buffer
);
217 case Formattable::kDouble
:
219 sprintf( convert
, "%lf", obj
.getDouble() );
220 stream
<< convert
<< "D";
222 case Formattable::kLong
:
223 stream
<< obj
.getLong() << "L";
225 case Formattable::kString
:
226 stream
<< "\"" << obj
.getString(buffer
) << "\"";
228 case Formattable::kArray
:
230 const Formattable
* array
;
231 array
= obj
.getArray(count
);
233 for (i
=0; i
<count
; ++i
) stream
<< array
[i
] << ( (i
==(count
-1)) ? "" : ", " );
237 stream
<< "INVALID_Formattable";
241 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
244 void TestMessageFormat::PatternTest()
246 Formattable testArgs
[] = {
247 Formattable(double(1)), Formattable(double(3456)),
248 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate
)
250 UnicodeString testCases
[] = {
251 "Quotes '', '{', 'a' {0} '{0}'",
252 "Quotes '', '{', 'a' {0,number} '{0}'",
253 "'{'1,number,'#',##} {1,number,'#',##}",
254 "There are {1} files on {2} at {3}.",
255 "On {2}, there are {1} files, with {0,number,currency}.",
256 "'{1,number,percent}', {1,number,percent},",
257 "'{1,date,full}', {1,date,full},",
258 "'{3,date,full}', {3,date,full},",
259 "'{1,number,#,##}' {1,number,#,##}",
262 // ICU 4.8 returns the original pattern (testCases),
263 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
264 /*UnicodeString testResultPatterns[] = {
265 "Quotes '', '{', a {0} '{'0}",
266 "Quotes '', '{', a {0,number} '{'0}",
267 "'{'1,number,#,##} {1,number,'#'#,##}",
268 "There are {1} files on {2} at {3}.",
269 "On {2}, there are {1} files, with {0,number,currency}.",
270 "'{'1,number,percent}, {1,number,percent},",
271 "'{'1,date,full}, {1,date,full},",
272 "'{'3,date,full}, {3,date,full},",
273 "'{'1,number,#,##} {1,number,#,##}"
276 UnicodeString testResultStrings
[] = {
277 "Quotes ', {, 'a' 1 {0}",
278 "Quotes ', {, 'a' 1 {0}",
279 "{1,number,'#',##} #34,56",
280 "There are 3,456 files on Disk at 1/12/70 5:46 AM.",
281 "On Disk, there are 3,456 files, with $1.00.",
282 "{1,number,percent}, 345,600%,",
283 "{1,date,full}, Wednesday, December 31, 1969,",
284 "{3,date,full}, Monday, January 12, 1970,",
285 "{1,number,#,##} 34,56"
289 for (int32_t i
= 0; i
< 9; ++i
) {
290 //it_out << "\nPat in: " << testCases[i]);
292 MessageFormat
*form
= 0;
293 UErrorCode success
= U_ZERO_ERROR
;
294 UnicodeString buffer
;
295 form
= new MessageFormat(testCases
[i
], Locale::getUS(), success
);
296 if (U_FAILURE(success
)) {
297 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success
));
298 logln(((UnicodeString
)"MessageFormat for ") + testCases
[i
] + " creation failed.\n");
301 // ICU 4.8 returns the original pattern (testCases),
302 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
303 if (form
->toPattern(buffer
) != testCases
[i
]) {
304 // Note: An alternative test would be to build MessagePattern objects for
305 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
307 // (Too much trouble...)
308 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i
);
309 //form->toPattern(buffer);
310 errln(((UnicodeString
)" Orig: ") + testCases
[i
]);
311 errln(((UnicodeString
)" Exp: ") + testCases
[i
]);
312 errln(((UnicodeString
)" Got: ") + buffer
);
315 //it_out << "Pat out: " << form->toPattern(buffer));
316 UnicodeString result
;
318 FieldPosition
fieldpos(0);
319 form
->format(testArgs
, count
, result
, fieldpos
, success
);
320 if (U_FAILURE(success
)) {
321 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success
));
322 logln("TestMessageFormat::PatternTest failed test #3");
325 if (result
!= testResultStrings
[i
]) {
326 errln("TestMessageFormat::PatternTest failed test #4");
327 logln("TestMessageFormat::PatternTest failed #4.");
328 logln(UnicodeString(" Result: ") + result
);
329 logln(UnicodeString(" Expected: ") + testResultStrings
[i
] );
333 //it_out << "Result: " << result);
335 /* TODO: Look at this test and see if this is still a valid test */
336 logln("---------------- test parse ----------------");
338 form
->toPattern(buffer
);
339 logln("MSG pattern for parse: " + buffer
);
341 int32_t parseCount
= 0;
342 Formattable
* values
= form
->parse(result
, parseCount
, success
);
343 if (U_FAILURE(success
)) {
344 errln("MessageFormat failed test #5");
345 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success
);
346 } else if (parseCount
!= count
) {
347 errln("MSG count not %d as expected. Got %d", count
, parseCount
);
349 UBool failed
= FALSE
;
350 for (int32_t j
= 0; j
< parseCount
; ++j
) {
351 if (values
== 0 || testArgs
[j
] != values
[j
]) {
352 errln(((UnicodeString
)"MSG testargs[") + j
+ "]: " + toString(testArgs
[j
]));
353 errln(((UnicodeString
)"MSG values[") + j
+ "] : " + toString(values
[j
]));
358 errln("MessageFormat failed test #6");
364 void TestMessageFormat::sample()
366 MessageFormat
*form
= 0;
367 UnicodeString buffer1
, buffer2
;
368 UErrorCode success
= U_ZERO_ERROR
;
369 form
= new MessageFormat("There are {0} files on {1}", success
);
370 if (U_FAILURE(success
)) {
371 errln("Err: Message format creation failed");
372 logln("Sample message format creation failed.");
375 UnicodeString
abc("abc");
376 UnicodeString
def("def");
377 Formattable testArgs1
[] = { abc
, def
};
378 FieldPosition
fieldpos(0);
379 assertEquals("format",
380 "There are abc files on def",
381 form
->format(testArgs1
, 2, buffer2
, fieldpos
, success
));
382 assertSuccess("format", success
);
386 void TestMessageFormat::testStaticFormat()
388 UErrorCode err
= U_ZERO_ERROR
;
389 Formattable arguments
[] = {
391 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
392 "a disturbance in the Force"
395 UnicodeString result
;
396 result
= MessageFormat::format(
397 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
403 if (U_FAILURE(err
)) {
404 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err
));
405 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err
);
409 const UnicodeString
expected(
410 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
411 if (result
!= expected
) {
412 errln("TestMessageFormat::testStaticFormat failed on test");
413 logln( UnicodeString(" Result: ") + result
);
414 logln( UnicodeString(" Expected: ") + expected
);
418 /* When the default locale is tr, make sure that the pattern can still be parsed. */
419 void TestMessageFormat::TestTurkishCasing()
421 UErrorCode err
= U_ZERO_ERROR
;
422 Locale saveDefaultLocale
;
423 Locale::setDefault( Locale("tr"), err
);
425 Formattable arguments
[] = {
427 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
428 "a disturbance in the Force"
431 UnicodeString result
;
432 result
= MessageFormat::format(
433 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
439 if (U_FAILURE(err
)) {
440 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err
));
444 const UnicodeString
expected(
445 "At 12:20:00 on 08.08.1997, there was a disturbance in the Force on planet 7.", "");
446 if (result
!= expected
) {
447 errln("TestTurkishCasing failed on test");
448 errln( UnicodeString(" Result: ") + result
);
449 errln( UnicodeString(" Expected: ") + expected
);
451 Locale::setDefault( saveDefaultLocale
, err
);
454 void TestMessageFormat::testSimpleFormat(/* char* par */)
456 logln("running TestMessageFormat::testSimpleFormat");
458 UErrorCode err
= U_ZERO_ERROR
;
460 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
461 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
462 Formattable testArgs3
[] = {(int32_t)12, "MyDisk"};
464 MessageFormat
* form
= new MessageFormat(
465 "The disk \"{1}\" contains {0} file(s).", err
);
467 UnicodeString string
;
468 FieldPosition
ignore(FieldPosition::DONT_CARE
);
469 form
->format(testArgs1
, 2, string
, ignore
, err
);
470 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 0 file(s).") {
471 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err
));
474 ignore
.setField(FieldPosition::DONT_CARE
);
476 form
->format(testArgs2
, 2, string
, ignore
, err
);
477 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 1 file(s).") {
479 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string
+ " - " + u_errorName(err
));
482 ignore
.setField(FieldPosition::DONT_CARE
);
484 form
->format(testArgs3
, 2, string
, ignore
, err
);
485 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 12 file(s).") {
486 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string
+ " - " + u_errorName(err
));
492 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
494 logln("running TestMessageFormat::testMsgFormatChoice");
496 UErrorCode err
= U_ZERO_ERROR
;
498 MessageFormat
* form
= new MessageFormat("The disk \"{1}\" contains {0}.", err
);
499 double filelimits
[] = {0,1,2};
500 UnicodeString filepart
[] = {"no files","one file","{0,number} files"};
501 ChoiceFormat
* fileform
= new ChoiceFormat(filelimits
, filepart
, 3);
502 form
->setFormat(1,*fileform
); // NOT zero, see below
503 //is the format adopted?
505 FieldPosition
ignore(FieldPosition::DONT_CARE
);
506 UnicodeString string
;
507 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
508 form
->format(testArgs1
, 2, string
, ignore
, err
);
509 if (string
!= "The disk \"MyDisk\" contains no files.") {
510 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
513 ignore
.setField(FieldPosition::DONT_CARE
);
515 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
516 form
->format(testArgs2
, 2, string
, ignore
, err
);
517 if (string
!= "The disk \"MyDisk\" contains one file.") {
518 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
521 ignore
.setField(FieldPosition::DONT_CARE
);
523 Formattable testArgs3
[] = {(int32_t)1273, "MyDisk"};
524 form
->format(testArgs3
, 2, string
, ignore
, err
);
525 if (string
!= "The disk \"MyDisk\" contains 1,273 files.") {
526 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err
));
534 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
536 logln("running TestMessageFormat::testMsgFormatPlural");
538 UErrorCode err
= U_ZERO_ERROR
;
539 UnicodeString
t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
540 UnicodeString
t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
541 UnicodeString
t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory.");
542 UnicodeString
t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory.");
543 UnicodeString
t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.");
544 MessageFormat
* mfNum
= new MessageFormat(t1
, Locale("fr"), err
);
545 if (U_FAILURE(err
)) {
546 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err
));
547 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
550 Formattable
testArgs1((int32_t)0);
551 FieldPosition
ignore(FieldPosition::DONT_CARE
);
552 UnicodeString numResult1
;
553 mfNum
->format(&testArgs1
, 1, numResult1
, ignore
, err
);
555 MessageFormat
* mfAlpha
= new MessageFormat(t2
, Locale("fr"), err
);
556 UnicodeString argName
[] = {UnicodeString("argument")};
557 UnicodeString argNameResult
;
558 mfAlpha
->format(argName
, &testArgs1
, 1, argNameResult
, err
);
559 if (U_FAILURE(err
)) {
560 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err
));
561 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
565 if ( numResult1
!= argNameResult
){
566 errln("TestMessageFormat::testMsgFormatPlural #1");
567 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
569 if ( numResult1
!= UnicodeString("C\'est 0 fichier dans la liste.")) {
570 errln("TestMessageFormat::testMsgFormatPlural #1");
571 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
578 MessageFormat
* mfNum2
= new MessageFormat(t3
, Locale("ru"), err
);
580 Formattable
testArgs2((int32_t)4);
581 mfNum2
->format(&testArgs2
, 1, numResult1
, ignore
, err
);
582 MessageFormat
* mfAlpha2
= new MessageFormat(t4
, Locale("ru"), err
);
583 argNameResult
.remove();
584 mfAlpha2
->format(argName
, &testArgs2
, 1, argNameResult
, err
);
586 if (U_FAILURE(err
)) {
587 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
588 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err
);
592 if ( numResult1
!= argNameResult
){
593 errln("TestMessageFormat::testMsgFormatPlural #2");
594 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
596 if ( numResult1
!= UnicodeString("There are 4,0 zavoda in the directory.")) {
597 errln("TestMessageFormat::testMsgFormatPlural #2");
598 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
606 MessageFormat
* msgFmt
= new MessageFormat(t5
, Locale("fr"), err
);
607 if (U_FAILURE(err
)) {
608 errln("TestMessageFormat::test nested PluralFormat with argumentName");
609 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err
);
613 Formattable
testArgs3((int32_t)0);
614 argNameResult
.remove();
615 msgFmt
->format(&testArgs3
, 1, argNameResult
, ignore
, err
);
616 if (U_FAILURE(err
)) {
617 errln("TestMessageFormat::test nested PluralFormat with argumentName");
619 if ( argNameResult
!= UnicodeString("C'est 0,0 fichier dans la liste.")) {
620 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult
);
621 logln(UnicodeString("The unexpected nested named PluralFormat."));
626 void TestMessageFormat::testApostropheInPluralAndSelect() {
627 UErrorCode errorCode
= U_ZERO_ERROR
;
628 MessageFormat
msgFmt(UNICODE_STRING_SIMPLE(
629 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"),
630 Locale::getEnglish(),
632 if (U_FAILURE(errorCode
)) {
633 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode
));
636 UnicodeString expected
= UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
637 Formattable args
[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
639 &msgFmt
, args
, 2, expected
,
640 "MessageFormat with apostrophes in plural/select arguments failed:\n");
643 void TestMessageFormat::internalFormat(MessageFormat
* msgFmt
,
644 Formattable
* args
, int32_t numOfArgs
,
645 UnicodeString expected
, const char* errMsg
)
647 UnicodeString result
;
648 FieldPosition
ignore(FieldPosition::DONT_CARE
);
649 UErrorCode status
= U_ZERO_ERROR
;
651 //Format with passed arguments
652 msgFmt
->format( args
, numOfArgs
, result
, ignore
, status
);
653 if (U_FAILURE(status
)) {
654 dataerrln( "%serror while formatting with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
656 //Compare expected with obtained result
657 if ( result
!= expected
) {
658 UnicodeString err
= UnicodeString(errMsg
);
659 err
+= UnicodeString(":Unexpected Result \n Expected: " + expected
+ "\n Obtained: " + result
+ "\n");
664 MessageFormat
* TestMessageFormat::internalCreate(
665 UnicodeString pattern
,Locale locale
,UErrorCode
&status
, char* errMsg
)
667 //Create the MessageFormat with simple SelectFormat
668 MessageFormat
* msgFmt
= new MessageFormat(pattern
, locale
, status
);
669 if (U_FAILURE(status
)) {
670 dataerrln( "%serror while constructing with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
671 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status
);
677 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
679 logln("running TestMessageFormat::testMsgFormatSelect");
681 UErrorCode err
= U_ZERO_ERROR
;
683 UnicodeString
t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
686 //Create the MessageFormat with simple French pattern
687 MessageFormat
* msgFmt1
= internalCreate(t1
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t1");
688 if (!U_FAILURE(err
)) {
690 Formattable testArgs10
[] = {"Kirti","female"};
691 Formattable testArgs11
[] = {"Victor","other"};
692 Formattable testArgs12
[] = {"Ash","unknown"};
693 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
694 UnicodeString exp
[] = {
695 "Kirti est all\\u00E9e \\u00E0 Paris." ,
696 "Victor est all\\u00E9 \\u00E0 Paris.",
697 "Ash est all\\u00E9 \\u00E0 Paris."};
699 for( int i
=0; i
< 3; i
++){
700 internalFormat( msgFmt1
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
705 //Quoted French Pattern
706 UnicodeString
t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
708 //Create the MessageFormat with Quoted French pattern
709 MessageFormat
* msgFmt2
= internalCreate(t2
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t2");
710 if (!U_FAILURE(err
)) {
712 Formattable testArgs10
[] = {"Kirti","female"};
713 Formattable testArgs11
[] = {"Victor","other"};
714 Formattable testArgs12
[] = {"Ash","male"};
715 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
716 UnicodeString exp
[] = {
717 "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
718 "Victor est all\\u00E9 c'est \\u00E0 Paris.",
719 "Ash est all\\u00E9 c'est \\u00E0 Paris."};
721 for( int i
=0; i
< 3; i
++){
722 internalFormat( msgFmt2
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
728 UnicodeString
t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
730 //Create the MessageFormat with English pattern
731 MessageFormat
* msgFmt3
= internalCreate(t3
, Locale("en"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t3");
732 if (!U_FAILURE(err
)) {
734 Formattable testArgs10
[] = {"female"};
735 Formattable testArgs11
[] = {"other"};
736 Formattable testArgs12
[] = {"male"};
737 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
738 UnicodeString exp
[] = {
739 "FEMALE FR company published new books." ,
740 "FR otherValue published new books.",
741 "MALE FR company published new books."};
743 for( int i
=0; i
< 3; i
++){
744 internalFormat( msgFmt3
, testArgs
[i
], 1, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
749 //Nested patterns with plural, number ,choice ,select format etc.
750 //Select Format with embedded number format
751 UnicodeString
t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
752 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
753 MessageFormat
* msgFmt4
= internalCreate(t4
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t4");
754 if (!U_FAILURE(err
)) {
756 Formattable testArgs10
[] = {"Kirti","female",(int32_t)6};
757 Formattable testArgs11
[] = {"Kirti","female",100.100};
758 Formattable testArgs12
[] = {"Kirti","other",(int32_t)6};
759 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
760 UnicodeString exp
[] = {
761 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
762 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
763 "Kirti est all\\u00E9 \\u00E0 Paris."};
765 for( int i
=0; i
< 3; i
++){
766 internalFormat( msgFmt4
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
772 //Plural format with embedded select format
773 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.");
775 //Create the MessageFormat with Plural format with embedded select format(nested pattern)
776 MessageFormat
* msgFmt5
= internalCreate(t5
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t5");
777 if (!U_FAILURE(err
)) {
779 Formattable testArgs10
[] = {"Kirti",(int32_t)6,"female"};
780 Formattable testArgs11
[] = {"Kirti",(int32_t)1,"female"};
781 Formattable testArgs12
[] = {"Ash",(int32_t)1,"other"};
782 Formattable testArgs13
[] = {"Ash",(int32_t)5,"other"};
783 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
};
784 UnicodeString exp
[] = {
785 "Kirti sont all\\u00E9es \\u00E0 Paris." ,
786 "Kirti est all\\u00E9e \\u00E0 Paris.",
787 "Ash est all\\u00E9 \\u00E0 Paris.",
788 "Ash sont all\\u00E9s \\u00E0 Paris."};
790 for( int i
=0; i
< 4; i
++){
791 internalFormat( msgFmt5
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
797 //Select, plural, and number formats heavily nested
798 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.");
799 //Create the MessageFormat with Select, plural, and number formats heavily nested
800 MessageFormat
* msgFmt6
= internalCreate(t6
, Locale("de"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t6");
801 if (!U_FAILURE(err
)) {
803 Formattable testArgs10
[] = {"Kirti","other",(int32_t)1,"other"};
804 Formattable testArgs11
[] = {"Kirti","other",(int32_t)6,"other"};
805 Formattable testArgs12
[] = {"Kirti","other",(int32_t)1,"female"};
806 Formattable testArgs13
[] = {"Kirti","other",(int32_t)3,"female"};
807 Formattable testArgs14
[] = {"Kirti","female",(int32_t)1,"female"};
808 Formattable testArgs15
[] = {"Kirti","female",(int32_t)5,"female"};
809 Formattable testArgs16
[] = {"Kirti","female",(int32_t)1,"other"};
810 Formattable testArgs17
[] = {"Kirti","female",(int32_t)5,"other"};
811 Formattable testArgs18
[] = {"Kirti","mixed",(int32_t)1,"mixed"};
812 Formattable testArgs19
[] = {"Kirti","mixed",(int32_t)1,"other"};
813 Formattable testArgs20
[] = {"Kirti","female",(int32_t)1,"mixed"};
814 Formattable testArgs21
[] = {"Kirti","mixed",(int32_t)5,"mixed"};
815 Formattable testArgs22
[] = {"Kirti","mixed",(int32_t)5,"other"};
816 Formattable testArgs23
[] = {"Kirti","female",(int32_t)5,"mixed"};
817 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
,
818 testArgs14
,testArgs15
,testArgs16
,testArgs17
,
819 testArgs18
,testArgs19
,testArgs20
,testArgs21
,
820 testArgs22
,testArgs23
};
821 UnicodeString exp
[] = {
822 "Kirti und sein Freund gingen nach Paris." ,
823 "Kirti und seine 6 Freunde gingen nach Paris." ,
824 "Kirti und seine Freundin gingen nach Paris.",
825 "Kirti und seine 3 Freundinnen gingen nach Paris.",
826 "Kirti und ihre Freundin gingen nach Paris.",
827 "Kirti und ihre 5 Freundinnen gingen nach Paris.",
828 "Kirti und ihr Freund gingen nach Paris.",
829 "Kirti und ihre 5 Freunde gingen nach Paris.",
830 "Kirti und sein Freund gingen nach Paris.",
831 "Kirti und sein Freund gingen nach Paris.",
832 "Kirti und ihr Freund gingen nach Paris.",
833 "Kirti und seine 5 Freunde gingen nach Paris." ,
834 "Kirti und seine 5 Freunde gingen nach Paris." ,
835 "Kirti und ihre 5 Freunde gingen nach Paris."
838 for( int i
=0; i
< 14; i
++){
839 internalFormat( msgFmt6
, testArgs
[i
], 4, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
845 //---------------------------------
847 //---------------------------------
849 void TestMessageFormat::testCopyConstructor()
851 UErrorCode success
= U_ZERO_ERROR
;
852 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
853 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
854 MessageFormat
*y
= 0;
855 y
= new MessageFormat(*x
);
859 logln("First test (operator ==): Passed!");
861 errln("TestMessageFormat::testCopyConstructor failed #1");
862 logln("First test (operator ==): Failed!");
864 if ( ((*x
== *y
) && (*y
== *x
)) &&
865 ((*x
!= *z
) && (*z
!= *x
)) &&
866 ((*y
!= *z
) && (*z
!= *y
)) )
867 logln("Second test (equals): Passed!");
869 errln("TestMessageFormat::testCopyConstructor failed #2");
870 logln("Second test (equals): Failed!");
879 void TestMessageFormat::testAssignment()
881 UErrorCode success
= U_ZERO_ERROR
;
882 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
883 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
884 MessageFormat
*y
= new MessageFormat("There are {0} files on {1} created", success
);
889 logln("First test (operator ==): Passed!");
891 errln( "TestMessageFormat::testAssignment failed #1");
892 logln("First test (operator ==): Failed!");
894 if ( ((*x
== *y
) && (*y
== *x
)) &&
895 ((*x
!= *z
) && (*z
!= *x
)) &&
896 ((*y
!= *z
) && (*z
!= *y
)) )
897 logln("Second test (equals): Passed!");
899 errln("TestMessageFormat::testAssignment failed #2");
900 logln("Second test (equals): Failed!");
908 void TestMessageFormat::testClone()
910 UErrorCode success
= U_ZERO_ERROR
;
911 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
912 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
913 MessageFormat
*y
= 0;
914 y
= (MessageFormat
*)x
->clone();
918 logln("First test (operator ==): Passed!");
920 errln("TestMessageFormat::testClone failed #1");
921 logln("First test (operator ==): Failed!");
923 if ( ((*x
== *y
) && (*y
== *x
)) &&
924 ((*x
!= *z
) && (*z
!= *x
)) &&
925 ((*y
!= *z
) && (*z
!= *y
)) )
926 logln("Second test (equals): Passed!");
928 errln("TestMessageFormat::testClone failed #2");
929 logln("Second test (equals): Failed!");
937 void TestMessageFormat::testEquals()
939 UErrorCode success
= U_ZERO_ERROR
;
940 MessageFormat
x("There are {0} files on {1}", success
);
941 MessageFormat
y("There are {0} files on {1}", success
);
943 errln( "TestMessageFormat::testEquals failed #1");
944 logln("First test (operator ==): Failed!");
949 void TestMessageFormat::testNotEquals()
951 UErrorCode success
= U_ZERO_ERROR
;
952 MessageFormat
x("There are {0} files on {1}", success
);
954 y
.setLocale(Locale("fr"));
956 errln( "TestMessageFormat::testEquals failed #1");
957 logln("First test (operator !=): Failed!");
960 y
.applyPattern("There are {0} files on {1} the disk", success
);
962 errln( "TestMessageFormat::testEquals failed #1");
963 logln("Second test (operator !=): Failed!");
968 void TestMessageFormat::testSetLocale()
970 UErrorCode err
= U_ZERO_ERROR
;
971 GregorianCalendar
cal(err
);
972 Formattable arguments
[] = {
974 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
978 UnicodeString result
;
980 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
981 UnicodeString formatStr
= "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
982 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
983 // Just use unlocalized currency symbol.
984 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
985 UnicodeString compareStrEng
= "At <time> on Aug 8, 1997, you made a deposit of ";
986 compareStrEng
+= (UChar
) 0x00a4;
987 compareStrEng
+= "456.83.";
988 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
989 // Just use unlocalized currency symbol.
990 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
991 UnicodeString compareStrGer
= "At <time> on 08.08.1997, you made a deposit of ";
992 compareStrGer
+= "456,83";
993 compareStrGer
+= (UChar
) 0x00a0;
994 compareStrGer
+= (UChar
) 0x00a4;
995 compareStrGer
+= ".";
997 MessageFormat
msg( formatStr
, err
);
999 FieldPosition
pos(0);
1000 result
= msg
.format(
1008 if (result
!= compareStrEng
) {
1009 dataerrln("*** MSG format err. - %s", u_errorName(err
));
1012 msg
.setLocale(Locale::getEnglish());
1013 UBool getLocale_ok
= TRUE
;
1014 if (msg
.getLocale() != Locale::getEnglish()) {
1015 errln("*** MSG getLocal err.");
1016 getLocale_ok
= FALSE
;
1019 msg
.setLocale(Locale::getGerman());
1021 if (msg
.getLocale() != Locale::getGerman()) {
1022 errln("*** MSG getLocal err.");
1023 getLocale_ok
= FALSE
;
1026 msg
.applyPattern( formatStr
, err
);
1030 result
= msg
.format(
1038 if (result
== compareStrGer
) {
1039 logln("MSG setLocale tested.");
1041 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err
));
1045 logln("MSG getLocale tested.");
1049 void TestMessageFormat::testFormat()
1051 UErrorCode err
= U_ZERO_ERROR
;
1052 GregorianCalendar
cal(err
);
1054 const Formattable ftarray
[] =
1056 Formattable( UDate(8.71068e+011), Formattable::kIsDate
)
1058 const int32_t ft_cnt
= sizeof(ftarray
) / sizeof(Formattable
);
1059 Formattable
ft_arr( ftarray
, ft_cnt
);
1061 Formattable
* fmt
= new Formattable(UDate(8.71068e+011), Formattable::kIsDate
);
1063 UnicodeString result
;
1065 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
1066 UnicodeString formatStr
= "On {0,date}, it began.";
1067 UnicodeString compareStr
= "On Aug 8, 1997, it began.";
1070 MessageFormat
msg( formatStr
, err
);
1071 FieldPosition
fp(0);
1075 result
= msg
.format(
1082 if (err
!= U_ILLEGAL_ARGUMENT_ERROR
) {
1083 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err
));
1089 result
= msg
.format(
1096 logln("MSG format( Formattable&, ... ) expected:" + compareStr
);
1097 logln("MSG format( Formattable&, ... ) result:" + result
);
1098 if (result
!= compareStr
) {
1099 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err
));
1101 logln("MSG format( Formattable&, ... ) tested.");
1108 void TestMessageFormat::testParse()
1110 UErrorCode err
= U_ZERO_ERROR
;
1112 UnicodeString msgFormatString
= "{0} =sep= {1}";
1113 MessageFormat
msg( msgFormatString
, err
);
1114 UnicodeString source
= "abc =sep= def";
1115 UnicodeString tmp1
, tmp2
;
1117 Formattable
* fmt_arr
= msg
.parse( source
, count
, err
);
1118 if (U_FAILURE(err
) || (!fmt_arr
)) {
1119 errln("*** MSG parse (ustring, count, err) error.");
1121 logln("MSG parse -- count: %d", count
);
1123 errln("*** MSG parse (ustring, count, err) count err.");
1125 if ((fmt_arr
[0].getType() == Formattable::kString
)
1126 && (fmt_arr
[1].getType() == Formattable::kString
)
1127 && (fmt_arr
[0].getString(tmp1
) == "abc")
1128 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1129 logln("MSG parse (ustring, count, err) tested.");
1131 errln("*** MSG parse (ustring, count, err) result err.");
1137 ParsePosition
pp(0);
1139 fmt_arr
= msg
.parse( source
, pp
, count
);
1140 if ((pp
== 0) || (!fmt_arr
)) {
1141 errln("*** MSG parse (ustring, parsepos., count) error.");
1143 logln("MSG parse -- count: %d", count
);
1145 errln("*** MSG parse (ustring, parsepos., count) count err.");
1147 if ((fmt_arr
[0].getType() == Formattable::kString
)
1148 && (fmt_arr
[1].getType() == Formattable::kString
)
1149 && (fmt_arr
[0].getString(tmp1
) == "abc")
1150 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1151 logln("MSG parse (ustring, parsepos., count) tested.");
1153 errln("*** MSG parse (ustring, parsepos., count) result err.");
1162 msg
.parseObject( source
, fmta
, pp
);
1164 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1166 logln("MSG parse -- count: %d", count
);
1167 fmta
.getArray(count
);
1169 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1171 if ((fmta
[0].getType() == Formattable::kString
)
1172 && (fmta
[1].getType() == Formattable::kString
)
1173 && (fmta
[0].getString(tmp1
) == "abc")
1174 && (fmta
[1].getString(tmp2
) == "def")) {
1175 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
1177 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1184 void TestMessageFormat::testAdopt()
1186 UErrorCode err
= U_ZERO_ERROR
;
1188 UnicodeString
formatStr("{0,date},{1},{2,number}", "");
1189 UnicodeString
formatStrChange("{0,number},{1,number},{2,date}", "");
1191 MessageFormat
msg( formatStr
, err
);
1192 MessageFormat
msgCmp( formatStr
, err
);
1193 if (U_FAILURE(err
)) {
1194 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err
));
1197 int32_t count
, countCmp
;
1198 const Format
** formats
= msg
.getFormats(count
);
1199 const Format
** formatsCmp
= msgCmp
.getFormats(countCmp
);
1200 const Format
** formatsChg
= 0;
1201 const Format
** formatsAct
= 0;
1205 UnicodeString patCmp
;
1206 UnicodeString patAct
;
1207 Format
** formatsToAdopt
;
1209 if (!formats
|| !formatsCmp
|| (count
<= 0) || (count
!= countCmp
)) {
1210 dataerrln("Error getting Formats");
1216 for (i
= 0; i
< count
; i
++) {
1219 if ((a
!= NULL
) && (b
!= NULL
)) {
1224 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1225 errln("(a != NULL) || (b != NULL)");
1230 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1232 formatsChg
= msg
.getFormats(countChg
); // tested function
1233 if (!formatsChg
|| (countChg
!= count
)) {
1234 errln("Error getting Formats");
1240 for (i
= 0; i
< count
; i
++) {
1243 if ((a
!= NULL
) && (b
!= NULL
)) {
1245 logln("formatsChg == formatsCmp at index %d", i
);
1251 errln("*** MSG getFormats diff err.");
1255 logln("MSG getFormats tested.");
1257 msg
.setFormats( formatsCmp
, countCmp
); //tested function
1259 formatsAct
= msg
.getFormats(countAct
);
1260 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1261 errln("Error getting Formats");
1265 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1266 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1267 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1268 msg
.toPattern(patCmp
.remove());
1269 if (!patCmp
.isBogus()) {
1270 errln("msg.setFormat().toPattern() succeeds.");
1273 for (i
= 0; i
< countAct
; i
++) {
1276 if ((a
!= NULL
) && (b
!= NULL
)) {
1278 logln("formatsAct != formatsCmp at index %d", i
);
1282 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1283 errln("(a != NULL) || (b != NULL)");
1287 logln("MSG setFormats tested.");
1291 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1293 formatsToAdopt
= new Format
* [countCmp
];
1294 if (!formatsToAdopt
) {
1295 errln("memory allocation error");
1299 for (i
= 0; i
< countCmp
; i
++) {
1300 if (formatsCmp
[i
] == NULL
) {
1301 formatsToAdopt
[i
] = NULL
;
1303 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1304 if (!formatsToAdopt
[i
]) {
1305 errln("Can't clone format at index %d", i
);
1310 msg
.adoptFormats( formatsToAdopt
, countCmp
); // function to test
1311 delete[] formatsToAdopt
;
1313 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1314 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1315 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1317 formatsAct
= msg
.getFormats(countAct
);
1318 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1319 errln("Error getting Formats");
1323 for (i
= 0; i
< countAct
; i
++) {
1326 if ((a
!= NULL
) && (b
!= NULL
)) {
1331 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1332 errln("(a != NULL) || (b != NULL)");
1336 logln("MSG adoptFormats tested.");
1340 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1342 formatsToAdopt
= new Format
* [countCmp
];
1343 if (!formatsToAdopt
) {
1344 errln("memory allocation error");
1348 for (i
= 0; i
< countCmp
; i
++) {
1349 if (formatsCmp
[i
] == NULL
) {
1350 formatsToAdopt
[i
] = NULL
;
1352 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1353 if (!formatsToAdopt
[i
]) {
1354 errln("Can't clone format at index %d", i
);
1360 for ( i
= 0; i
< countCmp
; i
++ ) {
1361 msg
.adoptFormat( i
, formatsToAdopt
[i
] ); // function to test
1363 delete[] formatsToAdopt
; // array itself not needed in this case;
1365 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1366 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1367 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1369 formatsAct
= msg
.getFormats(countAct
);
1370 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1371 errln("Error getting Formats");
1375 for (i
= 0; i
< countAct
; i
++) {
1378 if ((a
!= NULL
) && (b
!= NULL
)) {
1383 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1384 errln("(a != NULL) || (b != NULL)");
1388 logln("MSG adoptFormat tested.");
1391 // This test is a regression test for a fixed bug in the copy constructor.
1392 // It is kept as a global function rather than as a method since the test depends on memory values.
1393 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1394 // which is probably why it didn't show up in the regular test for the copy constructor.)
1395 // For this reason, the test isn't changed even though it contains function calls whose results are
1396 // not tested and had no problems. Actually, the test failed by *crashing*.
1397 static void _testCopyConstructor2()
1399 UErrorCode status
= U_ZERO_ERROR
;
1400 UnicodeString
formatStr("Hello World on {0,date,full}", "");
1401 UnicodeString
resultStr(" ", "");
1402 UnicodeString result
;
1403 FieldPosition
fp(0);
1404 UDate d
= Calendar::getNow();
1405 const Formattable
fargs( d
, Formattable::kIsDate
);
1407 MessageFormat
* fmt1
= new MessageFormat( formatStr
, status
);
1408 MessageFormat
* fmt2
= NULL
;
1409 MessageFormat
* fmt3
= NULL
;
1410 MessageFormat
* fmt4
= NULL
;
1413 it_err("testCopyConstructor2: (fmt1 != NULL)");
1417 fmt2
= new MessageFormat( *fmt1
);
1418 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1421 it_err("testCopyConstructor2: (fmt2 != NULL)");
1425 fmt3
= (MessageFormat
*) fmt1
->clone();
1426 fmt4
= (MessageFormat
*) fmt2
->clone();
1429 it_err("testCopyConstructor2: (fmt3 != NULL)");
1433 it_err("testCopyConstructor2: (fmt4 != NULL)");
1437 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1438 result
= fmt2
->format( &fargs
, 1, resultStr
, fp
, status
);
1439 result
= fmt3
->format( &fargs
, 1, resultStr
, fp
, status
);
1440 result
= fmt4
->format( &fargs
, 1, resultStr
, fp
, status
);
1449 void TestMessageFormat::testCopyConstructor2() {
1450 _testCopyConstructor2();
1454 * Verify that MessageFormat accomodates more than 10 arguments and
1455 * more than 10 subformats.
1457 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1458 UErrorCode ec
= U_ZERO_ERROR
;
1459 const UnicodeString pattern
=
1460 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1461 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1462 "there were {1,number} werjes "
1463 "(a {3,number,percent} increase over {2,number}) "
1464 "despite the {4}''s efforts "
1465 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1466 MessageFormat
msg(pattern
, ec
);
1467 if (U_FAILURE(ec
)) {
1468 dataerrln("FAIL: constructor failed - %s", u_errorName(ec
));
1472 const Formattable ARGS
[] = {
1473 Formattable(UDate(1e13
), Formattable::kIsDate
),
1474 Formattable((int32_t)1303),
1475 Formattable((int32_t)1202),
1476 Formattable(1303.0/1202 - 1),
1477 Formattable("Glimmung"),
1478 Formattable("the printers"),
1479 Formattable("Nick"),
1480 Formattable("his father"),
1481 Formattable("his mother"),
1482 Formattable("the spiddles"),
1483 Formattable("of course"),
1484 Formattable("Horace"),
1486 const int32_t ARGS_LENGTH
= sizeof(ARGS
) / sizeof(ARGS
[0]);
1487 Formattable
ARGS_OBJ(ARGS
, ARGS_LENGTH
);
1489 UnicodeString expected
=
1490 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1491 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1492 "there were 1,303 werjes "
1493 "(a 8% increase over 1,202) "
1494 "despite the Glimmung's efforts "
1495 "and to delight of the printers, Nick, his father, "
1496 "his mother, the spiddles, and of course Horace.";
1497 UnicodeString result
;
1498 msg
.format(ARGS_OBJ
, result
, ec
);
1499 if (result
== expected
) {
1502 errln((UnicodeString
)"FAIL: Got " + result
+
1503 ", expected " + expected
);
1507 // test RBNF extensions to message format
1508 void TestMessageFormat::TestRBNF(void) {
1509 // WARNING: this depends on the RBNF formats for en_US
1510 Locale
locale("en", "US", "");
1512 UErrorCode ec
= U_ZERO_ERROR
;
1514 UnicodeString values
[] = {
1515 // decimal values do not format completely for ordinal or duration, and
1516 // do not always parse, so do not include them
1517 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1519 int32_t values_count
= sizeof(values
)/sizeof(values
[0]);
1521 UnicodeString formats
[] = {
1522 "There are {0,spellout} files to search.",
1523 "There are {0,spellout,%simplified} files to search.",
1524 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1525 "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
1526 "Searching this file will take {0,duration} to complete.",
1527 "Searching this file will take {0,duration,%with-words} to complete.",
1529 int32_t formats_count
= sizeof(formats
)/sizeof(formats
[0]);
1531 Formattable args
[1];
1533 NumberFormat
* numFmt
= NumberFormat::createInstance(locale
, ec
);
1534 if (U_FAILURE(ec
)) {
1535 dataerrln("Error calling NumberFormat::createInstance()");
1539 for (int i
= 0; i
< formats_count
; ++i
) {
1540 MessageFormat
* fmt
= new MessageFormat(formats
[i
], locale
, ec
);
1541 logln((UnicodeString
)"Testing format pattern: '" + formats
[i
] + "'");
1543 for (int j
= 0; j
< values_count
; ++j
) {
1545 numFmt
->parse(values
[j
], args
[0], ec
);
1546 if (U_FAILURE(ec
)) {
1547 errln((UnicodeString
)"Failed to parse test argument " + values
[j
]);
1549 FieldPosition
fp(0);
1550 UnicodeString result
;
1551 fmt
->format(args
, 1, result
, fp
, ec
);
1552 logln((UnicodeString
)"value: " + toString(args
[0]) + " --> " + result
+ UnicodeString(" ec: ") + u_errorName(ec
));
1554 if (i
!= 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1556 Formattable
* parseResult
= fmt
->parse(result
, count
, ec
);
1558 errln((UnicodeString
)"parse returned " + count
+ " args");
1559 } else if (parseResult
[0] != args
[0]) {
1560 errln((UnicodeString
)"parsed argument " + toString(parseResult
[0]) + " != " + toString(args
[0]));
1562 delete []parseResult
;
1571 UnicodeString
TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern
& pattern
) {
1572 UnicodeString
us(pattern
.getPatternString());
1573 int count
= pattern
.countParts();
1574 for (int i
= count
; i
> 0;) {
1575 const MessagePattern::Part
& part
= pattern
.getPart(--i
);
1576 if (part
.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX
) {
1577 us
.remove(part
.getIndex(), part
.getLimit() - part
.getIndex());
1583 void TestMessageFormat::TestApostropheMode() {
1584 UErrorCode status
= U_ZERO_ERROR
;
1585 MessagePattern
*ado_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL
, status
);
1586 MessagePattern
*adr_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED
, status
);
1587 if (ado_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1588 errln("wrong value from ado_mp->getApostropheMode().");
1590 if (adr_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1591 errln("wrong value from adr_mp->getApostropheMode().");
1595 UnicodeString tuples
[] = {
1597 // DOUBLE_OPTIONAL pattern
1598 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1599 "I see {many}", "I see '{many}'", "",
1600 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1601 "I dont know", "I dont know", "I don't know",
1602 "I don't know", "I don't know", "I don''t know",
1603 "I don't know", "I don''t know", "I don''t know"
1605 int32_t tuples_count
= LENGTHOF(tuples
);
1607 for (int i
= 0; i
< tuples_count
; i
+= 3) {
1608 UnicodeString
& desired
= tuples
[i
];
1609 UnicodeString
& ado_pattern
= tuples
[i
+ 1];
1610 UErrorCode status
= U_ZERO_ERROR
;
1611 assertEquals("DOUBLE_OPTIONAL failure",
1613 GetPatternAndSkipSyntax(ado_mp
->parse(ado_pattern
, NULL
, status
)));
1614 UnicodeString
& adr_pattern
= tuples
[i
+ 2].isEmpty() ? ado_pattern
: tuples
[i
+ 2];
1615 assertEquals("DOUBLE_REQUIRED failure", desired
,
1616 GetPatternAndSkipSyntax(adr_mp
->parse(adr_pattern
, NULL
, status
)));
1623 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
1624 void TestMessageFormat::TestCompatibleApostrophe() {
1625 // Message with choice argument which does not contain another argument.
1626 // The JDK performs only one apostrophe-quoting pass on this pattern.
1627 UnicodeString pattern
= "ab{0,choice,0#1'2''3'''4''''.}yz";
1629 UErrorCode ec
= U_ZERO_ERROR
;
1630 MessageFormat
compMsg("", Locale::getUS(), ec
);
1631 compMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_REQUIRED
, NULL
, ec
);
1632 if (compMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1633 errln("wrong value from compMsg.getApostropheMode().");
1636 MessageFormat
icuMsg("", Locale::getUS(), ec
);
1637 icuMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_OPTIONAL
, NULL
, ec
);
1638 if (icuMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1639 errln("wrong value from icuMsg.getApostropheMode().");
1642 Formattable zero0
[] = { (int32_t)0 };
1643 FieldPosition
fieldpos(0);
1644 UnicodeString buffer1
, buffer2
;
1645 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1647 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1648 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1650 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1652 // Message with choice argument which contains a nested simple argument.
1653 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1656 pattern
= "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1657 compMsg
.applyPattern(pattern
, ec
);
1658 icuMsg
.applyPattern(pattern
, ec
);
1659 if (U_FAILURE(ec
)) {
1660 dataerrln("Unable to applyPattern - %s", u_errorName(ec
));
1662 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1664 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1665 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1666 "ab1'2'3''4''.#x0yz",
1667 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1670 // This part is copied over from Java tests but cannot be properly tested here
1671 // because we do not have a live reference implementation with JDK behavior.
1672 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1674 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1675 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1678 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1679 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1680 "12'3'4''.{0,number,#x}",
1685 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1686 const char* patterns
[] = { // pattern, expected pattern
1697 "{'a{}'a}'a", "{'a{}'a}''a",
1699 "'} '{'}'", "'} '{'}''",
1700 "'} {{{''", "'} {{{'''",
1702 int32_t pattern_count
= sizeof(patterns
)/sizeof(patterns
[0]);
1704 for (int i
= 0; i
< pattern_count
; i
+= 2) {
1705 UErrorCode status
= U_ZERO_ERROR
;
1706 UnicodeString result
= MessageFormat::autoQuoteApostrophe(patterns
[i
], status
);
1707 UnicodeString
target(patterns
[i
+1]);
1708 if (target
!= result
) {
1709 const int BUF2_LEN
= 64;
1711 char buf2
[BUF2_LEN
];
1712 int32_t len
= result
.extract(0, result
.length(), buf2
, BUF2_LEN
);
1713 if (len
>= BUF2_LEN
) {
1714 buf2
[BUF2_LEN
-1] = 0;
1716 sprintf(buf
, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i
/2, patterns
[i
], patterns
[i
+1], buf2
);
1722 void TestMessageFormat::testCoverage(void) {
1723 UErrorCode status
= U_ZERO_ERROR
;
1724 UnicodeString
testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1725 MessageFormat
*msgfmt
= new MessageFormat(testformat
, Locale("fr"), status
);
1726 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1727 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status
));
1730 if (!msgfmt
->usesNamedArguments()) {
1731 errln("FAIL: Unable to detect usage of named arguments.");
1733 const double limit
[] = {0.0, 1.0, 2.0};
1734 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
1737 ChoiceFormat
cf(limit
, formats
, 3);
1739 msgfmt
->setFormat("set", cf
, status
);
1741 StringEnumeration
*en
= msgfmt
->getFormatNames(status
);
1742 if (en
== NULL
|| U_FAILURE(status
)) {
1743 errln("FAIL: Unable to get format names enumeration.");
1747 count
= en
->count(status
);
1748 if (U_FAILURE(status
)) {
1749 errln("FAIL: Unable to get format name enumeration count.");
1751 for (int32_t i
= 0; i
< count
; i
++) {
1753 if (U_FAILURE(status
)) {
1754 errln("FAIL: Error enumerating through names.");
1761 // adoptFormat() takes ownership of the input Format object.
1762 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1763 Format
*cfClone
= cf
.clone();
1764 msgfmt
->adoptFormat("adopt", cfClone
, status
);
1769 msgfmt
= new MessageFormat("'", status
);
1770 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1771 errln("FAIL: Unable to create MessageFormat.");
1774 if (msgfmt
->usesNamedArguments()) {
1775 errln("FAIL: Unable to detect usage of named arguments.");
1778 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1779 // on a MessageFormat without named arguments.
1780 msgfmt
->setFormat("formatName", cf
, status
);
1781 if (U_FAILURE(status
)) {
1782 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1784 status
= U_ZERO_ERROR
;
1785 en
= msgfmt
->getFormatNames(status
);
1786 if (U_FAILURE(status
)) {
1787 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1794 void TestMessageFormat::TestTrimArgumentName() {
1795 // ICU 4.8 allows and ignores white space around argument names and numbers.
1796 IcuTestErrorCode
errorCode(*this, "TestTrimArgumentName");
1797 MessageFormat
m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode
);
1798 if (errorCode
.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1801 Formattable args
[1] = { (int32_t)2 };
1802 FieldPosition
ignore(0);
1803 UnicodeString result
;
1804 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1805 m
.format(args
, 1, result
, ignore
, errorCode
));
1807 m
.applyPattern("x { _oOo_ , number , integer } y", errorCode
);
1808 UnicodeString argName
= UNICODE_STRING_SIMPLE("_oOo_");
1811 assertEquals("trim-named-arg format() failed", "x 3 y",
1812 m
.format(&argName
, args
, 1, result
, errorCode
));
1815 #endif /* #if !UCONFIG_NO_FORMATTING */