1 /********************************************************************
3 * Copyright (c) 1997-2012, 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/localpointer.h"
25 #include "unicode/locid.h"
26 #include "unicode/msgfmt.h"
27 #include "unicode/numfmt.h"
28 #include "unicode/choicfmt.h"
29 #include "unicode/messagepattern.h"
30 #include "unicode/selfmt.h"
31 #include "unicode/gregocal.h"
34 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
37 TestMessageFormat::runIndexedTest(int32_t index
, UBool exec
,
38 const char* &name
, char* /*par*/) {
40 TESTCASE_AUTO(testBug1
);
41 TESTCASE_AUTO(testBug2
);
42 TESTCASE_AUTO(sample
);
43 TESTCASE_AUTO(PatternTest
);
44 TESTCASE_AUTO(testStaticFormat
);
45 TESTCASE_AUTO(testSimpleFormat
);
46 TESTCASE_AUTO(testMsgFormatChoice
);
47 TESTCASE_AUTO(testCopyConstructor
);
48 TESTCASE_AUTO(testAssignment
);
49 TESTCASE_AUTO(testClone
);
50 TESTCASE_AUTO(testEquals
);
51 TESTCASE_AUTO(testNotEquals
);
52 TESTCASE_AUTO(testSetLocale
);
53 TESTCASE_AUTO(testFormat
);
54 TESTCASE_AUTO(testParse
);
55 TESTCASE_AUTO(testAdopt
);
56 TESTCASE_AUTO(testCopyConstructor2
);
57 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats
);
58 TESTCASE_AUTO(TestRBNF
);
59 TESTCASE_AUTO(TestTurkishCasing
);
60 TESTCASE_AUTO(testAutoQuoteApostrophe
);
61 TESTCASE_AUTO(testMsgFormatPlural
);
62 TESTCASE_AUTO(testMsgFormatSelect
);
63 TESTCASE_AUTO(testApostropheInPluralAndSelect
);
64 TESTCASE_AUTO(TestApostropheMode
);
65 TESTCASE_AUTO(TestCompatibleApostrophe
);
66 TESTCASE_AUTO(testCoverage
);
67 TESTCASE_AUTO(testGetFormatNames
);
68 TESTCASE_AUTO(TestTrimArgumentName
);
69 TESTCASE_AUTO(TestSelectOrdinal
);
73 void TestMessageFormat::testBug3()
75 double myNumber
= -123456;
76 DecimalFormat
*form
= 0;
85 Locale("de", "AT", ""),
86 Locale("de", "CH", ""),
87 Locale("el", "", ""), // 10
88 Locale("en", "CA", ""),
89 Locale("en", "GB", ""),
90 Locale("en", "IE", ""),
91 Locale("en", "US", ""),
96 Locale("fr", "BE", ""),
97 Locale("fr", "CA", ""), // 20
98 Locale("fr", "CH", ""),
100 Locale("hr", "", ""),
101 Locale("hu", "", ""),
102 Locale("is", "", ""),
103 Locale("it", "", ""),
104 Locale("it", "CH", ""),
105 Locale("ja", "", ""),
106 Locale("ko", "", ""),
107 Locale("lt", "", ""), // 30
108 Locale("lv", "", ""),
109 Locale("mk", "", ""),
110 Locale("nl", "", ""),
111 Locale("nl", "BE", ""),
112 Locale("no", "", ""),
113 Locale("pl", "", ""),
114 Locale("pt", "", ""),
115 Locale("ro", "", ""),
116 Locale("ru", "", ""),
117 Locale("sh", "", ""), // 40
118 Locale("sk", "", ""),
119 Locale("sl", "", ""),
120 Locale("sq", "", ""),
121 Locale("sr", "", ""),
122 Locale("sv", "", ""),
123 Locale("tr", "", ""),
124 Locale("uk", "", ""),
125 Locale("zh", "", ""),
126 Locale("zh", "TW", "") // 49
129 for (i
= 0; i
< 49; i
++) {
130 UnicodeString buffer
;
131 logln(locale
[i
].getDisplayName(buffer
));
132 UErrorCode success
= U_ZERO_ERROR
;
133 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
134 form
= (DecimalFormat
*)NumberFormat::createInstance(locale
[i
], success
);
135 if (U_FAILURE(success
)) {
136 errln("Err: Number Format ");
137 logln("Number format creation failed.");
141 FieldPosition
pos(0);
143 form
->format(myNumber
, buffer
, pos
);
144 success
= U_ZERO_ERROR
;
145 ParsePosition parsePos
;
146 form
->parse(buffer
, result
, parsePos
);
147 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result
) + UnicodeString("[supposed output for result]"));
148 if (U_FAILURE(success
)) {
149 errln("Err: Number Format parse");
150 logln("Number format parse failed.");
156 void TestMessageFormat::testBug1()
158 const double limit
[] = {0.0, 1.0, 2.0};
159 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
162 ChoiceFormat
*cf
= new ChoiceFormat(limit
, formats
, 3);
163 FieldPosition
status(0);
164 UnicodeString toAppendTo
;
165 cf
->format((int32_t)1, toAppendTo
, status
);
166 if (toAppendTo
!= "1.0<=Arg<2.0") {
167 errln("ChoiceFormat cmp in testBug1");
173 void TestMessageFormat::testBug2()
175 UErrorCode status
= U_ZERO_ERROR
;
176 UnicodeString result
;
177 // {sfb} use double format in pattern, so result will match (not strictly necessary)
178 const UnicodeString pattern
= "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
179 logln("The input pattern : " + pattern
);
180 MessageFormat
*fmt
= new MessageFormat(pattern
, status
);
181 if (U_FAILURE(status
)) {
182 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status
));
185 logln("The output pattern is : " + fmt
->toPattern(result
));
186 if (pattern
!= result
) {
187 errln("MessageFormat::toPattern() failed.");
193 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
194 //----------------------------------------------------
196 //----------------------------------------------------
199 std::ostream
& operator<<(std::ostream
& stream
, const Formattable
& obj
);
201 #include "unicode/datefmt.h"
206 operator<<( IntlTest
& stream
,
207 const Formattable
& obj
)
209 static DateFormat
*defDateFormat
= 0;
211 UnicodeString buffer
;
212 switch(obj
.getType()) {
213 case Formattable::kDate
:
214 if (defDateFormat
== 0) {
215 defDateFormat
= DateFormat::createInstance();
217 defDateFormat
->format(obj
.getDate(), buffer
);
220 case Formattable::kDouble
:
222 sprintf( convert
, "%lf", obj
.getDouble() );
223 stream
<< convert
<< "D";
225 case Formattable::kLong
:
226 stream
<< obj
.getLong() << "L";
228 case Formattable::kString
:
229 stream
<< "\"" << obj
.getString(buffer
) << "\"";
231 case Formattable::kArray
:
233 const Formattable
* array
;
234 array
= obj
.getArray(count
);
236 for (i
=0; i
<count
; ++i
) stream
<< array
[i
] << ( (i
==(count
-1)) ? "" : ", " );
240 stream
<< "INVALID_Formattable";
244 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
247 void TestMessageFormat::PatternTest()
249 Formattable testArgs
[] = {
250 Formattable(double(1)), Formattable(double(3456)),
251 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate
)
253 UnicodeString testCases
[] = {
254 "Quotes '', '{', 'a' {0} '{0}'",
255 "Quotes '', '{', 'a' {0,number} '{0}'",
256 "'{'1,number,'#',##} {1,number,'#',##}",
257 "There are {1} files on {2} at {3}.",
258 "On {2}, there are {1} files, with {0,number,currency}.",
259 "'{1,number,percent}', {1,number,percent},",
260 "'{1,date,full}', {1,date,full},",
261 "'{3,date,full}', {3,date,full},",
262 "'{1,number,#,##}' {1,number,#,##}",
265 // ICU 4.8 returns the original pattern (testCases),
266 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
267 /*UnicodeString testResultPatterns[] = {
268 "Quotes '', '{', a {0} '{'0}",
269 "Quotes '', '{', a {0,number} '{'0}",
270 "'{'1,number,#,##} {1,number,'#'#,##}",
271 "There are {1} files on {2} at {3}.",
272 "On {2}, there are {1} files, with {0,number,currency}.",
273 "'{'1,number,percent}, {1,number,percent},",
274 "'{'1,date,full}, {1,date,full},",
275 "'{'3,date,full}, {3,date,full},",
276 "'{'1,number,#,##} {1,number,#,##}"
279 UnicodeString testResultStrings
[] = {
280 "Quotes ', {, 'a' 1 {0}",
281 "Quotes ', {, 'a' 1 {0}",
282 "{1,number,'#',##} #34,56",
283 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.",
284 "On Disk, there are 3,456 files, with $1.00.",
285 "{1,number,percent}, 345,600%,",
286 "{1,date,full}, Wednesday, December 31, 1969,",
287 "{3,date,full}, Monday, January 12, 1970,",
288 "{1,number,#,##} 34,56"
292 for (int32_t i
= 0; i
< 9; ++i
) {
293 //it_out << "\nPat in: " << testCases[i]);
295 MessageFormat
*form
= 0;
296 UErrorCode success
= U_ZERO_ERROR
;
297 UnicodeString buffer
;
298 form
= new MessageFormat(testCases
[i
], Locale::getUS(), success
);
299 if (U_FAILURE(success
)) {
300 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success
));
301 logln(((UnicodeString
)"MessageFormat for ") + testCases
[i
] + " creation failed.\n");
304 // ICU 4.8 returns the original pattern (testCases),
305 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
306 if (form
->toPattern(buffer
) != testCases
[i
]) {
307 // Note: An alternative test would be to build MessagePattern objects for
308 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
310 // (Too much trouble...)
311 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i
);
312 //form->toPattern(buffer);
313 errln(((UnicodeString
)" Orig: ") + testCases
[i
]);
314 errln(((UnicodeString
)" Exp: ") + testCases
[i
]);
315 errln(((UnicodeString
)" Got: ") + buffer
);
318 //it_out << "Pat out: " << form->toPattern(buffer));
319 UnicodeString result
;
321 FieldPosition
fieldpos(0);
322 form
->format(testArgs
, count
, result
, fieldpos
, success
);
323 if (U_FAILURE(success
)) {
324 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success
));
325 logln("TestMessageFormat::PatternTest failed test #3");
328 if (result
!= testResultStrings
[i
]) {
329 errln("TestMessageFormat::PatternTest failed test #4");
330 logln("TestMessageFormat::PatternTest failed #4.");
331 logln(UnicodeString(" Result: ") + result
);
332 logln(UnicodeString(" Expected: ") + testResultStrings
[i
] );
336 //it_out << "Result: " << result);
338 /* TODO: Look at this test and see if this is still a valid test */
339 logln("---------------- test parse ----------------");
341 form
->toPattern(buffer
);
342 logln("MSG pattern for parse: " + buffer
);
344 int32_t parseCount
= 0;
345 Formattable
* values
= form
->parse(result
, parseCount
, success
);
346 if (U_FAILURE(success
)) {
347 errln("MessageFormat failed test #5");
348 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success
);
349 } else if (parseCount
!= count
) {
350 errln("MSG count not %d as expected. Got %d", count
, parseCount
);
352 UBool failed
= FALSE
;
353 for (int32_t j
= 0; j
< parseCount
; ++j
) {
354 if (values
== 0 || testArgs
[j
] != values
[j
]) {
355 errln(((UnicodeString
)"MSG testargs[") + j
+ "]: " + toString(testArgs
[j
]));
356 errln(((UnicodeString
)"MSG values[") + j
+ "] : " + toString(values
[j
]));
361 errln("MessageFormat failed test #6");
367 void TestMessageFormat::sample()
369 MessageFormat
*form
= 0;
370 UnicodeString buffer1
, buffer2
;
371 UErrorCode success
= U_ZERO_ERROR
;
372 form
= new MessageFormat("There are {0} files on {1}", success
);
373 if (U_FAILURE(success
)) {
374 errln("Err: Message format creation failed");
375 logln("Sample message format creation failed.");
378 UnicodeString
abc("abc");
379 UnicodeString
def("def");
380 Formattable testArgs1
[] = { abc
, def
};
381 FieldPosition
fieldpos(0);
382 assertEquals("format",
383 "There are abc files on def",
384 form
->format(testArgs1
, 2, buffer2
, fieldpos
, success
));
385 assertSuccess("format", success
);
389 void TestMessageFormat::testStaticFormat()
391 UErrorCode err
= U_ZERO_ERROR
;
392 Formattable arguments
[] = {
394 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
395 "a disturbance in the Force"
398 UnicodeString result
;
399 result
= MessageFormat::format(
400 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
406 if (U_FAILURE(err
)) {
407 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err
));
408 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err
);
412 const UnicodeString
expected(
413 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
414 if (result
!= expected
) {
415 errln("TestMessageFormat::testStaticFormat failed on test");
416 logln( UnicodeString(" Result: ") + result
);
417 logln( UnicodeString(" Expected: ") + expected
);
421 /* When the default locale is tr, make sure that the pattern can still be parsed. */
422 void TestMessageFormat::TestTurkishCasing()
424 UErrorCode err
= U_ZERO_ERROR
;
425 Locale saveDefaultLocale
;
426 Locale::setDefault( Locale("tr"), err
);
428 Formattable arguments
[] = {
430 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
431 "a disturbance in the Force"
434 UnicodeString result
;
435 result
= MessageFormat::format(
436 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
442 if (U_FAILURE(err
)) {
443 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err
));
447 const UnicodeString
expected(
448 "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", "");
449 if (result
!= expected
) {
450 errln("TestTurkishCasing failed on test");
451 errln( UnicodeString(" Result: ") + result
);
452 errln( UnicodeString(" Expected: ") + expected
);
454 Locale::setDefault( saveDefaultLocale
, err
);
457 void TestMessageFormat::testSimpleFormat(/* char* par */)
459 logln("running TestMessageFormat::testSimpleFormat");
461 UErrorCode err
= U_ZERO_ERROR
;
463 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
464 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
465 Formattable testArgs3
[] = {(int32_t)12, "MyDisk"};
467 MessageFormat
* form
= new MessageFormat(
468 "The disk \"{1}\" contains {0} file(s).", err
);
470 UnicodeString string
;
471 FieldPosition
ignore(FieldPosition::DONT_CARE
);
472 form
->format(testArgs1
, 2, string
, ignore
, err
);
473 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 0 file(s).") {
474 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err
));
477 ignore
.setField(FieldPosition::DONT_CARE
);
479 form
->format(testArgs2
, 2, string
, ignore
, err
);
480 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 1 file(s).") {
482 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string
+ " - " + u_errorName(err
));
485 ignore
.setField(FieldPosition::DONT_CARE
);
487 form
->format(testArgs3
, 2, string
, ignore
, err
);
488 if (U_FAILURE(err
) || string
!= "The disk \"MyDisk\" contains 12 file(s).") {
489 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string
+ " - " + u_errorName(err
));
495 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
497 logln("running TestMessageFormat::testMsgFormatChoice");
499 UErrorCode err
= U_ZERO_ERROR
;
501 MessageFormat
* form
= new MessageFormat("The disk \"{1}\" contains {0}.", err
);
502 double filelimits
[] = {0,1,2};
503 UnicodeString filepart
[] = {"no files","one file","{0,number} files"};
504 ChoiceFormat
* fileform
= new ChoiceFormat(filelimits
, filepart
, 3);
505 form
->setFormat(1,*fileform
); // NOT zero, see below
506 //is the format adopted?
508 FieldPosition
ignore(FieldPosition::DONT_CARE
);
509 UnicodeString string
;
510 Formattable testArgs1
[] = {(int32_t)0, "MyDisk"};
511 form
->format(testArgs1
, 2, string
, ignore
, err
);
512 if (string
!= "The disk \"MyDisk\" contains no files.") {
513 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
516 ignore
.setField(FieldPosition::DONT_CARE
);
518 Formattable testArgs2
[] = {(int32_t)1, "MyDisk"};
519 form
->format(testArgs2
, 2, string
, ignore
, err
);
520 if (string
!= "The disk \"MyDisk\" contains one file.") {
521 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
524 ignore
.setField(FieldPosition::DONT_CARE
);
526 Formattable testArgs3
[] = {(int32_t)1273, "MyDisk"};
527 form
->format(testArgs3
, 2, string
, ignore
, err
);
528 if (string
!= "The disk \"MyDisk\" contains 1,273 files.") {
529 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err
));
537 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
539 logln("running TestMessageFormat::testMsgFormatPlural");
541 UErrorCode err
= U_ZERO_ERROR
;
542 UnicodeString
t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
543 UnicodeString
t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
544 UnicodeString
t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory.");
545 UnicodeString
t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory.");
546 UnicodeString
t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.");
547 MessageFormat
* mfNum
= new MessageFormat(t1
, Locale("fr"), err
);
548 if (U_FAILURE(err
)) {
549 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err
));
550 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
553 Formattable
testArgs1((int32_t)0);
554 FieldPosition
ignore(FieldPosition::DONT_CARE
);
555 UnicodeString numResult1
;
556 mfNum
->format(&testArgs1
, 1, numResult1
, ignore
, err
);
558 MessageFormat
* mfAlpha
= new MessageFormat(t2
, Locale("fr"), err
);
559 UnicodeString argName
[] = {UnicodeString("argument")};
560 UnicodeString argNameResult
;
561 mfAlpha
->format(argName
, &testArgs1
, 1, argNameResult
, err
);
562 if (U_FAILURE(err
)) {
563 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err
));
564 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err
);
568 if ( numResult1
!= argNameResult
){
569 errln("TestMessageFormat::testMsgFormatPlural #1");
570 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
572 if ( numResult1
!= UnicodeString("C\'est 0 fichier dans la liste.")) {
573 errln("TestMessageFormat::testMsgFormatPlural #1");
574 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
581 MessageFormat
* mfNum2
= new MessageFormat(t3
, Locale("ru"), err
);
583 Formattable
testArgs2((int32_t)4);
584 mfNum2
->format(&testArgs2
, 1, numResult1
, ignore
, err
);
585 MessageFormat
* mfAlpha2
= new MessageFormat(t4
, Locale("ru"), err
);
586 argNameResult
.remove();
587 mfAlpha2
->format(argName
, &testArgs2
, 1, argNameResult
, err
);
589 if (U_FAILURE(err
)) {
590 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
591 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err
);
595 if ( numResult1
!= argNameResult
){
596 errln("TestMessageFormat::testMsgFormatPlural #2");
597 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
599 if ( numResult1
!= UnicodeString("There are 4,0 zavoda in the directory.")) {
600 errln("TestMessageFormat::testMsgFormatPlural #2");
601 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
609 MessageFormat
* msgFmt
= new MessageFormat(t5
, Locale("fr"), err
);
610 if (U_FAILURE(err
)) {
611 errln("TestMessageFormat::test nested PluralFormat with argumentName");
612 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err
);
616 Formattable
testArgs3((int32_t)0);
617 argNameResult
.remove();
618 msgFmt
->format(&testArgs3
, 1, argNameResult
, ignore
, err
);
619 if (U_FAILURE(err
)) {
620 errln("TestMessageFormat::test nested PluralFormat with argumentName");
622 if ( argNameResult
!= UnicodeString("C'est 0,0 fichier dans la liste.")) {
623 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult
);
624 logln(UnicodeString("The unexpected nested named PluralFormat."));
629 void TestMessageFormat::testApostropheInPluralAndSelect() {
630 UErrorCode errorCode
= U_ZERO_ERROR
;
631 MessageFormat
msgFmt(UNICODE_STRING_SIMPLE(
632 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"),
633 Locale::getEnglish(),
635 if (U_FAILURE(errorCode
)) {
636 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode
));
639 UnicodeString expected
= UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
640 Formattable args
[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
642 &msgFmt
, args
, 2, expected
,
643 "MessageFormat with apostrophes in plural/select arguments failed:\n");
646 void TestMessageFormat::internalFormat(MessageFormat
* msgFmt
,
647 Formattable
* args
, int32_t numOfArgs
,
648 UnicodeString expected
, const char* errMsg
)
650 UnicodeString result
;
651 FieldPosition
ignore(FieldPosition::DONT_CARE
);
652 UErrorCode status
= U_ZERO_ERROR
;
654 //Format with passed arguments
655 msgFmt
->format( args
, numOfArgs
, result
, ignore
, status
);
656 if (U_FAILURE(status
)) {
657 dataerrln( "%serror while formatting with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
659 //Compare expected with obtained result
660 if ( result
!= expected
) {
661 UnicodeString err
= UnicodeString(errMsg
);
662 err
+= UnicodeString(":Unexpected Result \n Expected: " + expected
+ "\n Obtained: " + result
+ "\n");
667 MessageFormat
* TestMessageFormat::internalCreate(
668 UnicodeString pattern
,Locale locale
,UErrorCode
&status
, char* errMsg
)
670 //Create the MessageFormat with simple SelectFormat
671 MessageFormat
* msgFmt
= new MessageFormat(pattern
, locale
, status
);
672 if (U_FAILURE(status
)) {
673 dataerrln( "%serror while constructing with ErrorCode as %s" ,errMsg
, u_errorName(status
) );
674 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status
);
680 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
682 logln("running TestMessageFormat::testMsgFormatSelect");
684 UErrorCode err
= U_ZERO_ERROR
;
686 UnicodeString
t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
689 //Create the MessageFormat with simple French pattern
690 MessageFormat
* msgFmt1
= internalCreate(t1
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t1");
691 if (!U_FAILURE(err
)) {
693 Formattable testArgs10
[] = {"Kirti","female"};
694 Formattable testArgs11
[] = {"Victor","other"};
695 Formattable testArgs12
[] = {"Ash","unknown"};
696 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
697 UnicodeString exp
[] = {
698 "Kirti est all\\u00E9e \\u00E0 Paris." ,
699 "Victor est all\\u00E9 \\u00E0 Paris.",
700 "Ash est all\\u00E9 \\u00E0 Paris."};
702 for( int i
=0; i
< 3; i
++){
703 internalFormat( msgFmt1
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
708 //Quoted French Pattern
709 UnicodeString
t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
711 //Create the MessageFormat with Quoted French pattern
712 MessageFormat
* msgFmt2
= internalCreate(t2
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t2");
713 if (!U_FAILURE(err
)) {
715 Formattable testArgs10
[] = {"Kirti","female"};
716 Formattable testArgs11
[] = {"Victor","other"};
717 Formattable testArgs12
[] = {"Ash","male"};
718 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
719 UnicodeString exp
[] = {
720 "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
721 "Victor est all\\u00E9 c'est \\u00E0 Paris.",
722 "Ash est all\\u00E9 c'est \\u00E0 Paris."};
724 for( int i
=0; i
< 3; i
++){
725 internalFormat( msgFmt2
, testArgs
[i
], 2, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
731 UnicodeString
t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
733 //Create the MessageFormat with English pattern
734 MessageFormat
* msgFmt3
= internalCreate(t3
, Locale("en"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t3");
735 if (!U_FAILURE(err
)) {
737 Formattable testArgs10
[] = {"female"};
738 Formattable testArgs11
[] = {"other"};
739 Formattable testArgs12
[] = {"male"};
740 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
741 UnicodeString exp
[] = {
742 "FEMALE FR company published new books." ,
743 "FR otherValue published new books.",
744 "MALE FR company published new books."};
746 for( int i
=0; i
< 3; i
++){
747 internalFormat( msgFmt3
, testArgs
[i
], 1, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
752 //Nested patterns with plural, number ,choice ,select format etc.
753 //Select Format with embedded number format
754 UnicodeString
t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
755 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
756 MessageFormat
* msgFmt4
= internalCreate(t4
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t4");
757 if (!U_FAILURE(err
)) {
759 Formattable testArgs10
[] = {"Kirti","female",(int32_t)6};
760 Formattable testArgs11
[] = {"Kirti","female",100.100};
761 Formattable testArgs12
[] = {"Kirti","other",(int32_t)6};
762 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
};
763 UnicodeString exp
[] = {
764 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
765 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
766 "Kirti est all\\u00E9 \\u00E0 Paris."};
768 for( int i
=0; i
< 3; i
++){
769 internalFormat( msgFmt4
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
775 //Plural format with embedded select format
776 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.");
778 //Create the MessageFormat with Plural format with embedded select format(nested pattern)
779 MessageFormat
* msgFmt5
= internalCreate(t5
.unescape(), Locale("fr"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t5");
780 if (!U_FAILURE(err
)) {
782 Formattable testArgs10
[] = {"Kirti",(int32_t)6,"female"};
783 Formattable testArgs11
[] = {"Kirti",(int32_t)1,"female"};
784 Formattable testArgs12
[] = {"Ash",(int32_t)1,"other"};
785 Formattable testArgs13
[] = {"Ash",(int32_t)5,"other"};
786 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
};
787 UnicodeString exp
[] = {
788 "Kirti sont all\\u00E9es \\u00E0 Paris." ,
789 "Kirti est all\\u00E9e \\u00E0 Paris.",
790 "Ash est all\\u00E9 \\u00E0 Paris.",
791 "Ash sont all\\u00E9s \\u00E0 Paris."};
793 for( int i
=0; i
< 4; i
++){
794 internalFormat( msgFmt5
, testArgs
[i
], 3, exp
[i
].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
800 //Select, plural, and number formats heavily nested
801 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.");
802 //Create the MessageFormat with Select, plural, and number formats heavily nested
803 MessageFormat
* msgFmt6
= internalCreate(t6
, Locale("de"),err
,(char*)"From TestMessageFormat::TestSelectFormat create t6");
804 if (!U_FAILURE(err
)) {
806 Formattable testArgs10
[] = {"Kirti","other",(int32_t)1,"other"};
807 Formattable testArgs11
[] = {"Kirti","other",(int32_t)6,"other"};
808 Formattable testArgs12
[] = {"Kirti","other",(int32_t)1,"female"};
809 Formattable testArgs13
[] = {"Kirti","other",(int32_t)3,"female"};
810 Formattable testArgs14
[] = {"Kirti","female",(int32_t)1,"female"};
811 Formattable testArgs15
[] = {"Kirti","female",(int32_t)5,"female"};
812 Formattable testArgs16
[] = {"Kirti","female",(int32_t)1,"other"};
813 Formattable testArgs17
[] = {"Kirti","female",(int32_t)5,"other"};
814 Formattable testArgs18
[] = {"Kirti","mixed",(int32_t)1,"mixed"};
815 Formattable testArgs19
[] = {"Kirti","mixed",(int32_t)1,"other"};
816 Formattable testArgs20
[] = {"Kirti","female",(int32_t)1,"mixed"};
817 Formattable testArgs21
[] = {"Kirti","mixed",(int32_t)5,"mixed"};
818 Formattable testArgs22
[] = {"Kirti","mixed",(int32_t)5,"other"};
819 Formattable testArgs23
[] = {"Kirti","female",(int32_t)5,"mixed"};
820 Formattable
* testArgs
[] = {testArgs10
,testArgs11
,testArgs12
,testArgs13
,
821 testArgs14
,testArgs15
,testArgs16
,testArgs17
,
822 testArgs18
,testArgs19
,testArgs20
,testArgs21
,
823 testArgs22
,testArgs23
};
824 UnicodeString exp
[] = {
825 "Kirti und sein Freund gingen nach Paris." ,
826 "Kirti und seine 6 Freunde gingen nach Paris." ,
827 "Kirti und seine Freundin gingen nach Paris.",
828 "Kirti und seine 3 Freundinnen gingen nach Paris.",
829 "Kirti und ihre Freundin gingen nach Paris.",
830 "Kirti und ihre 5 Freundinnen gingen nach Paris.",
831 "Kirti und ihr Freund gingen nach Paris.",
832 "Kirti und ihre 5 Freunde gingen nach Paris.",
833 "Kirti und sein Freund gingen nach Paris.",
834 "Kirti und sein Freund gingen nach Paris.",
835 "Kirti und ihr Freund gingen nach Paris.",
836 "Kirti und seine 5 Freunde gingen nach Paris." ,
837 "Kirti und seine 5 Freunde gingen nach Paris." ,
838 "Kirti und ihre 5 Freunde gingen nach Paris."
841 for( int i
=0; i
< 14; i
++){
842 internalFormat( msgFmt6
, testArgs
[i
], 4, exp
[i
] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
848 //---------------------------------
850 //---------------------------------
852 void TestMessageFormat::testCopyConstructor()
854 UErrorCode success
= U_ZERO_ERROR
;
855 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
856 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
857 MessageFormat
*y
= 0;
858 y
= new MessageFormat(*x
);
862 logln("First test (operator ==): Passed!");
864 errln("TestMessageFormat::testCopyConstructor failed #1");
865 logln("First test (operator ==): Failed!");
867 if ( ((*x
== *y
) && (*y
== *x
)) &&
868 ((*x
!= *z
) && (*z
!= *x
)) &&
869 ((*y
!= *z
) && (*z
!= *y
)) )
870 logln("Second test (equals): Passed!");
872 errln("TestMessageFormat::testCopyConstructor failed #2");
873 logln("Second test (equals): Failed!");
882 void TestMessageFormat::testAssignment()
884 UErrorCode success
= U_ZERO_ERROR
;
885 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
886 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
887 MessageFormat
*y
= new MessageFormat("There are {0} files on {1} created", success
);
892 logln("First test (operator ==): Passed!");
894 errln( "TestMessageFormat::testAssignment failed #1");
895 logln("First test (operator ==): Failed!");
897 if ( ((*x
== *y
) && (*y
== *x
)) &&
898 ((*x
!= *z
) && (*z
!= *x
)) &&
899 ((*y
!= *z
) && (*z
!= *y
)) )
900 logln("Second test (equals): Passed!");
902 errln("TestMessageFormat::testAssignment failed #2");
903 logln("Second test (equals): Failed!");
911 void TestMessageFormat::testClone()
913 UErrorCode success
= U_ZERO_ERROR
;
914 MessageFormat
*x
= new MessageFormat("There are {0} files on {1}", success
);
915 MessageFormat
*z
= new MessageFormat("There are {0} files on {1} created", success
);
916 MessageFormat
*y
= 0;
917 y
= (MessageFormat
*)x
->clone();
921 logln("First test (operator ==): Passed!");
923 errln("TestMessageFormat::testClone failed #1");
924 logln("First test (operator ==): Failed!");
926 if ( ((*x
== *y
) && (*y
== *x
)) &&
927 ((*x
!= *z
) && (*z
!= *x
)) &&
928 ((*y
!= *z
) && (*z
!= *y
)) )
929 logln("Second test (equals): Passed!");
931 errln("TestMessageFormat::testClone failed #2");
932 logln("Second test (equals): Failed!");
940 void TestMessageFormat::testEquals()
942 UErrorCode success
= U_ZERO_ERROR
;
943 MessageFormat
x("There are {0} files on {1}", success
);
944 MessageFormat
y("There are {0} files on {1}", success
);
946 errln( "TestMessageFormat::testEquals failed #1");
947 logln("First test (operator ==): Failed!");
952 void TestMessageFormat::testNotEquals()
954 UErrorCode success
= U_ZERO_ERROR
;
955 MessageFormat
x("There are {0} files on {1}", success
);
957 y
.setLocale(Locale("fr"));
959 errln( "TestMessageFormat::testEquals failed #1");
960 logln("First test (operator !=): Failed!");
963 y
.applyPattern("There are {0} files on {1} the disk", success
);
965 errln( "TestMessageFormat::testEquals failed #1");
966 logln("Second test (operator !=): Failed!");
971 void TestMessageFormat::testSetLocale()
973 UErrorCode err
= U_ZERO_ERROR
;
974 GregorianCalendar
cal(err
);
975 Formattable arguments
[] = {
977 Formattable(UDate(8.71068e+011), Formattable::kIsDate
),
981 UnicodeString result
;
983 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
984 UnicodeString formatStr
= "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
985 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
986 // Just use unlocalized currency symbol.
987 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
988 UnicodeString compareStrEng
= "At <time> on Aug 8, 1997, you made a deposit of ";
989 compareStrEng
+= (UChar
) 0x00a4;
990 compareStrEng
+= "456.83.";
991 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
992 // Just use unlocalized currency symbol.
993 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
994 UnicodeString compareStrGer
= "At <time> on 08.08.1997, you made a deposit of ";
995 compareStrGer
+= "456,83";
996 compareStrGer
+= (UChar
) 0x00a0;
997 compareStrGer
+= (UChar
) 0x00a4;
998 compareStrGer
+= ".";
1000 MessageFormat
msg( formatStr
, err
);
1002 FieldPosition
pos(0);
1003 result
= msg
.format(
1011 if (result
!= compareStrEng
) {
1012 dataerrln("*** MSG format err. - %s", u_errorName(err
));
1015 msg
.setLocale(Locale::getEnglish());
1016 UBool getLocale_ok
= TRUE
;
1017 if (msg
.getLocale() != Locale::getEnglish()) {
1018 errln("*** MSG getLocal err.");
1019 getLocale_ok
= FALSE
;
1022 msg
.setLocale(Locale::getGerman());
1024 if (msg
.getLocale() != Locale::getGerman()) {
1025 errln("*** MSG getLocal err.");
1026 getLocale_ok
= FALSE
;
1029 msg
.applyPattern( formatStr
, err
);
1033 result
= msg
.format(
1041 if (result
== compareStrGer
) {
1042 logln("MSG setLocale tested.");
1044 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err
));
1048 logln("MSG getLocale tested.");
1052 void TestMessageFormat::testFormat()
1054 UErrorCode err
= U_ZERO_ERROR
;
1055 GregorianCalendar
cal(err
);
1057 const Formattable ftarray
[] =
1059 Formattable( UDate(8.71068e+011), Formattable::kIsDate
)
1061 const int32_t ft_cnt
= sizeof(ftarray
) / sizeof(Formattable
);
1062 Formattable
ft_arr( ftarray
, ft_cnt
);
1064 Formattable
* fmt
= new Formattable(UDate(8.71068e+011), Formattable::kIsDate
);
1066 UnicodeString result
;
1068 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
1069 UnicodeString formatStr
= "On {0,date}, it began.";
1070 UnicodeString compareStr
= "On Aug 8, 1997, it began.";
1073 MessageFormat
msg( formatStr
, err
);
1074 FieldPosition
fp(0);
1078 result
= msg
.format(
1085 if (err
!= U_ILLEGAL_ARGUMENT_ERROR
) {
1086 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err
));
1092 result
= msg
.format(
1099 logln("MSG format( Formattable&, ... ) expected:" + compareStr
);
1100 logln("MSG format( Formattable&, ... ) result:" + result
);
1101 if (result
!= compareStr
) {
1102 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err
));
1104 logln("MSG format( Formattable&, ... ) tested.");
1111 void TestMessageFormat::testParse()
1113 UErrorCode err
= U_ZERO_ERROR
;
1115 UnicodeString msgFormatString
= "{0} =sep= {1}";
1116 MessageFormat
msg( msgFormatString
, err
);
1117 UnicodeString source
= "abc =sep= def";
1118 UnicodeString tmp1
, tmp2
;
1120 Formattable
* fmt_arr
= msg
.parse( source
, count
, err
);
1121 if (U_FAILURE(err
) || (!fmt_arr
)) {
1122 errln("*** MSG parse (ustring, count, err) error.");
1124 logln("MSG parse -- count: %d", count
);
1126 errln("*** MSG parse (ustring, count, err) count err.");
1128 if ((fmt_arr
[0].getType() == Formattable::kString
)
1129 && (fmt_arr
[1].getType() == Formattable::kString
)
1130 && (fmt_arr
[0].getString(tmp1
) == "abc")
1131 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1132 logln("MSG parse (ustring, count, err) tested.");
1134 errln("*** MSG parse (ustring, count, err) result err.");
1140 ParsePosition
pp(0);
1142 fmt_arr
= msg
.parse( source
, pp
, count
);
1143 if ((pp
== 0) || (!fmt_arr
)) {
1144 errln("*** MSG parse (ustring, parsepos., count) error.");
1146 logln("MSG parse -- count: %d", count
);
1148 errln("*** MSG parse (ustring, parsepos., count) count err.");
1150 if ((fmt_arr
[0].getType() == Formattable::kString
)
1151 && (fmt_arr
[1].getType() == Formattable::kString
)
1152 && (fmt_arr
[0].getString(tmp1
) == "abc")
1153 && (fmt_arr
[1].getString(tmp2
) == "def")) {
1154 logln("MSG parse (ustring, parsepos., count) tested.");
1156 errln("*** MSG parse (ustring, parsepos., count) result err.");
1165 msg
.parseObject( source
, fmta
, pp
);
1167 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1169 logln("MSG parse -- count: %d", count
);
1170 fmta
.getArray(count
);
1172 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1174 if ((fmta
[0].getType() == Formattable::kString
)
1175 && (fmta
[1].getType() == Formattable::kString
)
1176 && (fmta
[0].getString(tmp1
) == "abc")
1177 && (fmta
[1].getString(tmp2
) == "def")) {
1178 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
1180 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1187 void TestMessageFormat::testAdopt()
1189 UErrorCode err
= U_ZERO_ERROR
;
1191 UnicodeString
formatStr("{0,date},{1},{2,number}", "");
1192 UnicodeString
formatStrChange("{0,number},{1,number},{2,date}", "");
1194 MessageFormat
msg( formatStr
, err
);
1195 MessageFormat
msgCmp( formatStr
, err
);
1196 if (U_FAILURE(err
)) {
1197 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err
));
1200 int32_t count
, countCmp
;
1201 const Format
** formats
= msg
.getFormats(count
);
1202 const Format
** formatsCmp
= msgCmp
.getFormats(countCmp
);
1203 const Format
** formatsChg
= 0;
1204 const Format
** formatsAct
= 0;
1208 UnicodeString patCmp
;
1209 UnicodeString patAct
;
1210 Format
** formatsToAdopt
;
1212 if (!formats
|| !formatsCmp
|| (count
<= 0) || (count
!= countCmp
)) {
1213 dataerrln("Error getting Formats");
1219 for (i
= 0; i
< count
; i
++) {
1222 if ((a
!= NULL
) && (b
!= NULL
)) {
1227 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1228 errln("(a != NULL) || (b != NULL)");
1233 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1235 formatsChg
= msg
.getFormats(countChg
); // tested function
1236 if (!formatsChg
|| (countChg
!= count
)) {
1237 errln("Error getting Formats");
1243 for (i
= 0; i
< count
; i
++) {
1246 if ((a
!= NULL
) && (b
!= NULL
)) {
1248 logln("formatsChg == formatsCmp at index %d", i
);
1254 errln("*** MSG getFormats diff err.");
1258 logln("MSG getFormats tested.");
1260 msg
.setFormats( formatsCmp
, countCmp
); //tested function
1262 formatsAct
= msg
.getFormats(countAct
);
1263 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1264 errln("Error getting Formats");
1268 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1269 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1270 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1271 msg
.toPattern(patCmp
.remove());
1272 if (!patCmp
.isBogus()) {
1273 errln("msg.setFormat().toPattern() succeeds.");
1276 for (i
= 0; i
< countAct
; i
++) {
1279 if ((a
!= NULL
) && (b
!= NULL
)) {
1281 logln("formatsAct != formatsCmp at index %d", i
);
1285 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1286 errln("(a != NULL) || (b != NULL)");
1290 logln("MSG setFormats tested.");
1294 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1296 formatsToAdopt
= new Format
* [countCmp
];
1297 if (!formatsToAdopt
) {
1298 errln("memory allocation error");
1302 for (i
= 0; i
< countCmp
; i
++) {
1303 if (formatsCmp
[i
] == NULL
) {
1304 formatsToAdopt
[i
] = NULL
;
1306 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1307 if (!formatsToAdopt
[i
]) {
1308 errln("Can't clone format at index %d", i
);
1313 msg
.adoptFormats( formatsToAdopt
, countCmp
); // function to test
1314 delete[] formatsToAdopt
;
1316 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1317 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1318 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1320 formatsAct
= msg
.getFormats(countAct
);
1321 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1322 errln("Error getting Formats");
1326 for (i
= 0; i
< countAct
; i
++) {
1329 if ((a
!= NULL
) && (b
!= NULL
)) {
1334 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1335 errln("(a != NULL) || (b != NULL)");
1339 logln("MSG adoptFormats tested.");
1343 msg
.applyPattern( formatStrChange
, err
); //set msg formats to something different
1345 formatsToAdopt
= new Format
* [countCmp
];
1346 if (!formatsToAdopt
) {
1347 errln("memory allocation error");
1351 for (i
= 0; i
< countCmp
; i
++) {
1352 if (formatsCmp
[i
] == NULL
) {
1353 formatsToAdopt
[i
] = NULL
;
1355 formatsToAdopt
[i
] = formatsCmp
[i
]->clone();
1356 if (!formatsToAdopt
[i
]) {
1357 errln("Can't clone format at index %d", i
);
1363 for ( i
= 0; i
< countCmp
; i
++ ) {
1364 msg
.adoptFormat( i
, formatsToAdopt
[i
] ); // function to test
1366 delete[] formatsToAdopt
; // array itself not needed in this case;
1368 assertEquals("msgCmp.toPattern()", formatStr
, msgCmp
.toPattern(patCmp
.remove()));
1369 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1370 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1372 formatsAct
= msg
.getFormats(countAct
);
1373 if (!formatsAct
|| (countAct
<=0) || (countAct
!= countCmp
)) {
1374 errln("Error getting Formats");
1378 for (i
= 0; i
< countAct
; i
++) {
1381 if ((a
!= NULL
) && (b
!= NULL
)) {
1386 }else if ((a
!= NULL
) || (b
!= NULL
)) {
1387 errln("(a != NULL) || (b != NULL)");
1391 logln("MSG adoptFormat tested.");
1394 // This test is a regression test for a fixed bug in the copy constructor.
1395 // It is kept as a global function rather than as a method since the test depends on memory values.
1396 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1397 // which is probably why it didn't show up in the regular test for the copy constructor.)
1398 // For this reason, the test isn't changed even though it contains function calls whose results are
1399 // not tested and had no problems. Actually, the test failed by *crashing*.
1400 static void _testCopyConstructor2()
1402 UErrorCode status
= U_ZERO_ERROR
;
1403 UnicodeString
formatStr("Hello World on {0,date,full}", "");
1404 UnicodeString
resultStr(" ", "");
1405 UnicodeString result
;
1406 FieldPosition
fp(0);
1407 UDate d
= Calendar::getNow();
1408 const Formattable
fargs( d
, Formattable::kIsDate
);
1410 MessageFormat
* fmt1
= new MessageFormat( formatStr
, status
);
1411 MessageFormat
* fmt2
= NULL
;
1412 MessageFormat
* fmt3
= NULL
;
1413 MessageFormat
* fmt4
= NULL
;
1416 it_err("testCopyConstructor2: (fmt1 != NULL)");
1420 fmt2
= new MessageFormat( *fmt1
);
1421 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1424 it_err("testCopyConstructor2: (fmt2 != NULL)");
1428 fmt3
= (MessageFormat
*) fmt1
->clone();
1429 fmt4
= (MessageFormat
*) fmt2
->clone();
1432 it_err("testCopyConstructor2: (fmt3 != NULL)");
1436 it_err("testCopyConstructor2: (fmt4 != NULL)");
1440 result
= fmt1
->format( &fargs
, 1, resultStr
, fp
, status
);
1441 result
= fmt2
->format( &fargs
, 1, resultStr
, fp
, status
);
1442 result
= fmt3
->format( &fargs
, 1, resultStr
, fp
, status
);
1443 result
= fmt4
->format( &fargs
, 1, resultStr
, fp
, status
);
1452 void TestMessageFormat::testCopyConstructor2() {
1453 _testCopyConstructor2();
1457 * Verify that MessageFormat accomodates more than 10 arguments and
1458 * more than 10 subformats.
1460 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1461 UErrorCode ec
= U_ZERO_ERROR
;
1462 const UnicodeString pattern
=
1463 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1464 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1465 "there were {1,number} werjes "
1466 "(a {3,number,percent} increase over {2,number}) "
1467 "despite the {4}''s efforts "
1468 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1469 MessageFormat
msg(pattern
, ec
);
1470 if (U_FAILURE(ec
)) {
1471 dataerrln("FAIL: constructor failed - %s", u_errorName(ec
));
1475 const Formattable ARGS
[] = {
1476 Formattable(UDate(1e13
), Formattable::kIsDate
),
1477 Formattable((int32_t)1303),
1478 Formattable((int32_t)1202),
1479 Formattable(1303.0/1202 - 1),
1480 Formattable("Glimmung"),
1481 Formattable("the printers"),
1482 Formattable("Nick"),
1483 Formattable("his father"),
1484 Formattable("his mother"),
1485 Formattable("the spiddles"),
1486 Formattable("of course"),
1487 Formattable("Horace"),
1489 const int32_t ARGS_LENGTH
= sizeof(ARGS
) / sizeof(ARGS
[0]);
1490 Formattable
ARGS_OBJ(ARGS
, ARGS_LENGTH
);
1492 UnicodeString expected
=
1493 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1494 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1495 "there were 1,303 werjes "
1496 "(a 8% increase over 1,202) "
1497 "despite the Glimmung's efforts "
1498 "and to delight of the printers, Nick, his father, "
1499 "his mother, the spiddles, and of course Horace.";
1500 UnicodeString result
;
1501 msg
.format(ARGS_OBJ
, result
, ec
);
1502 if (result
== expected
) {
1505 errln((UnicodeString
)"FAIL: Got " + result
+
1506 ", expected " + expected
);
1510 // test RBNF extensions to message format
1511 void TestMessageFormat::TestRBNF(void) {
1512 // WARNING: this depends on the RBNF formats for en_US
1513 Locale
locale("en", "US", "");
1515 UErrorCode ec
= U_ZERO_ERROR
;
1517 UnicodeString values
[] = {
1518 // decimal values do not format completely for ordinal or duration, and
1519 // do not always parse, so do not include them
1520 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1522 int32_t values_count
= sizeof(values
)/sizeof(values
[0]);
1524 UnicodeString formats
[] = {
1525 "There are {0,spellout} files to search.",
1526 "There are {0,spellout,%simplified} files to search.",
1527 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1528 "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
1529 "Searching this file will take {0,duration} to complete.",
1530 "Searching this file will take {0,duration,%with-words} to complete.",
1532 int32_t formats_count
= sizeof(formats
)/sizeof(formats
[0]);
1534 Formattable args
[1];
1536 NumberFormat
* numFmt
= NumberFormat::createInstance(locale
, ec
);
1537 if (U_FAILURE(ec
)) {
1538 dataerrln("Error calling NumberFormat::createInstance()");
1542 for (int i
= 0; i
< formats_count
; ++i
) {
1543 MessageFormat
* fmt
= new MessageFormat(formats
[i
], locale
, ec
);
1544 logln((UnicodeString
)"Testing format pattern: '" + formats
[i
] + "'");
1546 for (int j
= 0; j
< values_count
; ++j
) {
1548 numFmt
->parse(values
[j
], args
[0], ec
);
1549 if (U_FAILURE(ec
)) {
1550 errln((UnicodeString
)"Failed to parse test argument " + values
[j
]);
1552 FieldPosition
fp(0);
1553 UnicodeString result
;
1554 fmt
->format(args
, 1, result
, fp
, ec
);
1555 logln((UnicodeString
)"value: " + toString(args
[0]) + " --> " + result
+ UnicodeString(" ec: ") + u_errorName(ec
));
1557 if (i
!= 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1559 Formattable
* parseResult
= fmt
->parse(result
, count
, ec
);
1561 errln((UnicodeString
)"parse returned " + count
+ " args");
1562 } else if (parseResult
[0] != args
[0]) {
1563 errln((UnicodeString
)"parsed argument " + toString(parseResult
[0]) + " != " + toString(args
[0]));
1565 delete []parseResult
;
1574 UnicodeString
TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern
& pattern
) {
1575 UnicodeString
us(pattern
.getPatternString());
1576 int count
= pattern
.countParts();
1577 for (int i
= count
; i
> 0;) {
1578 const MessagePattern::Part
& part
= pattern
.getPart(--i
);
1579 if (part
.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX
) {
1580 us
.remove(part
.getIndex(), part
.getLimit() - part
.getIndex());
1586 void TestMessageFormat::TestApostropheMode() {
1587 UErrorCode status
= U_ZERO_ERROR
;
1588 MessagePattern
*ado_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL
, status
);
1589 MessagePattern
*adr_mp
= new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED
, status
);
1590 if (ado_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1591 errln("wrong value from ado_mp->getApostropheMode().");
1593 if (adr_mp
->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1594 errln("wrong value from adr_mp->getApostropheMode().");
1598 UnicodeString tuples
[] = {
1600 // DOUBLE_OPTIONAL pattern
1601 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1602 "I see {many}", "I see '{many}'", "",
1603 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1604 "I dont know", "I dont know", "I don't know",
1605 "I don't know", "I don't know", "I don''t know",
1606 "I don't know", "I don''t know", "I don''t know"
1608 int32_t tuples_count
= LENGTHOF(tuples
);
1610 for (int i
= 0; i
< tuples_count
; i
+= 3) {
1611 UnicodeString
& desired
= tuples
[i
];
1612 UnicodeString
& ado_pattern
= tuples
[i
+ 1];
1613 UErrorCode status
= U_ZERO_ERROR
;
1614 assertEquals("DOUBLE_OPTIONAL failure",
1616 GetPatternAndSkipSyntax(ado_mp
->parse(ado_pattern
, NULL
, status
)));
1617 UnicodeString
& adr_pattern
= tuples
[i
+ 2].isEmpty() ? ado_pattern
: tuples
[i
+ 2];
1618 assertEquals("DOUBLE_REQUIRED failure", desired
,
1619 GetPatternAndSkipSyntax(adr_mp
->parse(adr_pattern
, NULL
, status
)));
1626 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
1627 void TestMessageFormat::TestCompatibleApostrophe() {
1628 // Message with choice argument which does not contain another argument.
1629 // The JDK performs only one apostrophe-quoting pass on this pattern.
1630 UnicodeString pattern
= "ab{0,choice,0#1'2''3'''4''''.}yz";
1632 UErrorCode ec
= U_ZERO_ERROR
;
1633 MessageFormat
compMsg("", Locale::getUS(), ec
);
1634 compMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_REQUIRED
, NULL
, ec
);
1635 if (compMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED
) {
1636 errln("wrong value from compMsg.getApostropheMode().");
1639 MessageFormat
icuMsg("", Locale::getUS(), ec
);
1640 icuMsg
.applyPattern(pattern
, UMSGPAT_APOS_DOUBLE_OPTIONAL
, NULL
, ec
);
1641 if (icuMsg
.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL
) {
1642 errln("wrong value from icuMsg.getApostropheMode().");
1645 Formattable zero0
[] = { (int32_t)0 };
1646 FieldPosition
fieldpos(0);
1647 UnicodeString buffer1
, buffer2
;
1648 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1650 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1651 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1653 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1655 // Message with choice argument which contains a nested simple argument.
1656 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1659 pattern
= "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1660 compMsg
.applyPattern(pattern
, ec
);
1661 icuMsg
.applyPattern(pattern
, ec
);
1662 if (U_FAILURE(ec
)) {
1663 dataerrln("Unable to applyPattern - %s", u_errorName(ec
));
1665 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1667 compMsg
.format(zero0
, 1, buffer1
, fieldpos
, ec
));
1668 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1669 "ab1'2'3''4''.#x0yz",
1670 icuMsg
.format(zero0
, 1, buffer2
, fieldpos
, ec
));
1673 // This part is copied over from Java tests but cannot be properly tested here
1674 // because we do not have a live reference implementation with JDK behavior.
1675 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1677 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1678 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1681 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1682 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1683 "12'3'4''.{0,number,#x}",
1688 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1689 const char* patterns
[] = { // pattern, expected pattern
1700 "{'a{}'a}'a", "{'a{}'a}''a",
1702 "'} '{'}'", "'} '{'}''",
1703 "'} {{{''", "'} {{{'''",
1705 int32_t pattern_count
= sizeof(patterns
)/sizeof(patterns
[0]);
1707 for (int i
= 0; i
< pattern_count
; i
+= 2) {
1708 UErrorCode status
= U_ZERO_ERROR
;
1709 UnicodeString result
= MessageFormat::autoQuoteApostrophe(patterns
[i
], status
);
1710 UnicodeString
target(patterns
[i
+1]);
1711 if (target
!= result
) {
1712 const int BUF2_LEN
= 64;
1714 char buf2
[BUF2_LEN
];
1715 int32_t len
= result
.extract(0, result
.length(), buf2
, BUF2_LEN
);
1716 if (len
>= BUF2_LEN
) {
1717 buf2
[BUF2_LEN
-1] = 0;
1719 sprintf(buf
, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i
/2, patterns
[i
], patterns
[i
+1], buf2
);
1725 void TestMessageFormat::testCoverage(void) {
1726 UErrorCode status
= U_ZERO_ERROR
;
1727 UnicodeString
testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1728 MessageFormat
*msgfmt
= new MessageFormat(testformat
, Locale("fr"), status
);
1729 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1730 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status
));
1733 if (!msgfmt
->usesNamedArguments()) {
1734 errln("FAIL: Unable to detect usage of named arguments.");
1736 const double limit
[] = {0.0, 1.0, 2.0};
1737 const UnicodeString formats
[] = {"0.0<=Arg<1.0",
1740 ChoiceFormat
cf(limit
, formats
, 3);
1742 msgfmt
->setFormat("set", cf
, status
);
1744 StringEnumeration
*en
= msgfmt
->getFormatNames(status
);
1745 if (en
== NULL
|| U_FAILURE(status
)) {
1746 errln("FAIL: Unable to get format names enumeration.");
1750 count
= en
->count(status
);
1751 if (U_FAILURE(status
)) {
1752 errln("FAIL: Unable to get format name enumeration count.");
1754 for (int32_t i
= 0; i
< count
; i
++) {
1756 if (U_FAILURE(status
)) {
1757 errln("FAIL: Error enumerating through names.");
1764 // adoptFormat() takes ownership of the input Format object.
1765 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1766 Format
*cfClone
= cf
.clone();
1767 msgfmt
->adoptFormat("adopt", cfClone
, status
);
1772 msgfmt
= new MessageFormat("'", status
);
1773 if (msgfmt
== NULL
|| U_FAILURE(status
)) {
1774 errln("FAIL: Unable to create MessageFormat.");
1777 if (msgfmt
->usesNamedArguments()) {
1778 errln("FAIL: Unable to detect usage of named arguments.");
1781 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1782 // on a MessageFormat without named arguments.
1783 msgfmt
->setFormat("formatName", cf
, status
);
1784 if (U_FAILURE(status
)) {
1785 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1787 status
= U_ZERO_ERROR
;
1788 en
= msgfmt
->getFormatNames(status
);
1789 if (U_FAILURE(status
)) {
1790 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1797 void TestMessageFormat::testGetFormatNames() {
1798 IcuTestErrorCode
errorCode(*this, "testGetFormatNames");
1799 MessageFormat
msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode
);
1800 if(errorCode
.logDataIfFailureAndReset("MessageFormat() failed")) {
1803 LocalPointer
<StringEnumeration
> names(msgfmt
.getFormatNames(errorCode
));
1804 if(errorCode
.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1807 const UnicodeString
*name
;
1808 name
= names
->snext(errorCode
);
1809 if (name
== NULL
|| errorCode
.isFailure()) {
1810 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode
.errorName());
1814 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name
)) {
1817 name
= names
->snext(errorCode
);
1818 if (name
== NULL
|| errorCode
.isFailure()) {
1819 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode
.errorName());
1823 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name
)) {
1826 name
= names
->snext(errorCode
);
1827 if (name
== NULL
|| errorCode
.isFailure()) {
1828 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode
.errorName());
1832 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name
)) {
1835 name
= names
->snext(errorCode
);
1837 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name
);
1842 void TestMessageFormat::TestTrimArgumentName() {
1843 // ICU 4.8 allows and ignores white space around argument names and numbers.
1844 IcuTestErrorCode
errorCode(*this, "TestTrimArgumentName");
1845 MessageFormat
m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode
);
1846 if (errorCode
.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1849 Formattable args
[1] = { (int32_t)2 };
1850 FieldPosition
ignore(0);
1851 UnicodeString result
;
1852 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1853 m
.format(args
, 1, result
, ignore
, errorCode
));
1855 m
.applyPattern("x { _oOo_ , number , integer } y", errorCode
);
1856 UnicodeString argName
= UNICODE_STRING_SIMPLE("_oOo_");
1859 assertEquals("trim-named-arg format() failed", "x 3 y",
1860 m
.format(&argName
, args
, 1, result
, errorCode
));
1863 void TestMessageFormat::TestSelectOrdinal() {
1864 IcuTestErrorCode
errorCode(*this, "TestSelectOrdinal");
1865 // Test plural & ordinal together,
1866 // to make sure that we get the correct cached PluralSelector for each.
1868 "{0,plural,one{1 file}other{# files}}, "
1869 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
1870 Locale::getEnglish(), errorCode
);
1871 if (errorCode
.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1874 Formattable args
[1] = { (int32_t)21 };
1875 FieldPosition
ignore(0);
1876 UnicodeString result
;
1877 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file",
1878 m
.format(args
, 1, result
, ignore
, errorCode
), TRUE
);
1881 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1882 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1885 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1886 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1889 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1890 m
.format(args
, 1, result
.remove(), ignore
, errorCode
), TRUE
);
1892 errorCode
.logDataIfFailureAndReset("");
1895 #endif /* #if !UCONFIG_NO_FORMATTING */