1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************
6 * File TMSGFMT.CPP
7 *
8 * Modification History:
9 *
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 *******************************************************************/
15
16 #include "unicode/utypes.h"
17
18 #if !UCONFIG_NO_FORMATTING
19
20 #include "tmsgfmt.h"
21 #include "cmemory.h"
22
23 #include "unicode/format.h"
24 #include "unicode/decimfmt.h"
25 #include "unicode/localpointer.h"
26 #include "unicode/locid.h"
27 #include "unicode/msgfmt.h"
28 #include "unicode/numfmt.h"
29 #include "unicode/choicfmt.h"
30 #include "unicode/messagepattern.h"
31 #include "unicode/selfmt.h"
32 #include "unicode/gregocal.h"
33 #include <stdio.h>
34
35 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)36 TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
37 const char* &name, char* /*par*/) {
38 TESTCASE_AUTO_BEGIN;
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(testGetFormatNames);
67 TESTCASE_AUTO(TestTrimArgumentName);
68 TESTCASE_AUTO(TestSelectOrdinal);
69 TESTCASE_AUTO(TestDecimals);
70 TESTCASE_AUTO_END;
71 }
72
testBug3()73 void TestMessageFormat::testBug3()
74 {
75 double myNumber = -123456;
76 DecimalFormat *form = 0;
77 Locale locale[] = {
78 Locale("ar", "", ""),
79 Locale("be", "", ""),
80 Locale("bg", "", ""),
81 Locale("ca", "", ""),
82 Locale("cs", "", ""),
83 Locale("da", "", ""),
84 Locale("de", "", ""),
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", ""),
92 Locale("es", "", ""),
93 Locale("et", "", ""),
94 Locale("fi", "", ""),
95 Locale("fr", "", ""),
96 Locale("fr", "BE", ""),
97 Locale("fr", "CA", ""), // 20
98 Locale("fr", "CH", ""),
99 Locale("he", "", ""),
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
127 };
128 int32_t i;
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.");
138 continue;
139 }
140 Formattable result;
141 FieldPosition pos(0);
142 buffer.remove();
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.");
151 }
152 delete form;
153 }
154 }
155
testBug1()156 void TestMessageFormat::testBug1()
157 {
158 const double limit[] = {0.0, 1.0, 2.0};
159 const UnicodeString formats[] = {"0.0<=Arg<1.0",
160 "1.0<=Arg<2.0",
161 "2.0<-Arg"};
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");
168 }
169 logln(toAppendTo);
170 delete cf;
171 }
172
testBug2()173 void TestMessageFormat::testBug2()
174 {
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));
183 return;
184 }
185 logln("The output pattern is : " + fmt->toPattern(result));
186 if (pattern != result) {
187 errln("MessageFormat::toPattern() failed.");
188 }
189 delete fmt;
190 }
191
192 #if 0
193 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
194 //----------------------------------------------------
195 // console I/O
196 //----------------------------------------------------
197
198 #include <iostream>
199 std::ostream& operator<<(std::ostream& stream, const Formattable& obj);
200
201 #include "unicode/datefmt.h"
202 #include <stdlib.h>
203 #include <string.h>
204
205 IntlTest&
206 operator<<( IntlTest& stream,
207 const Formattable& obj)
208 {
209 static DateFormat *defDateFormat = 0;
210
211 UnicodeString buffer;
212 switch(obj.getType()) {
213 case Formattable::kDate :
214 if (defDateFormat == 0) {
215 defDateFormat = DateFormat::createInstance();
216 }
217 defDateFormat->format(obj.getDate(), buffer);
218 stream << buffer;
219 break;
220 case Formattable::kDouble :
221 char convert[20];
222 sprintf( convert, "%lf", obj.getDouble() );
223 stream << convert << "D";
224 break;
225 case Formattable::kLong :
226 stream << obj.getLong() << "L";
227 break;
228 case Formattable::kString:
229 stream << "\"" << obj.getString(buffer) << "\"";
230 break;
231 case Formattable::kArray:
232 int32_t i, count;
233 const Formattable* array;
234 array = obj.getArray(count);
235 stream << "[";
236 for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
237 stream << "]";
238 break;
239 default:
240 stream << "INVALID_Formattable";
241 }
242 return stream;
243 }
244 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
245 #endif
246
PatternTest()247 void TestMessageFormat::PatternTest()
248 {
249 Formattable testArgs[] = {
250 Formattable(double(1)), Formattable(double(3456)),
251 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
252 };
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,#,##}",
263 };
264
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,#,##}"
277 };*/
278
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"
289 };
290
291
292 for (int32_t i = 0; i < 9; ++i) {
293 //it_out << "\nPat in: " << testCases[i]);
294
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");
302 continue;
303 }
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.
309 // into account.
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);
316 }
317
318 //it_out << "Pat out: " << form->toPattern(buffer));
319 UnicodeString result;
320 int32_t count = 4;
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");
326 continue;
327 }
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] );
333 }
334
335
336 //it_out << "Result: " << result);
337 #if 0
338 /* TODO: Look at this test and see if this is still a valid test */
339 logln("---------------- test parse ----------------");
340
341 form->toPattern(buffer);
342 logln("MSG pattern for parse: " + buffer);
343
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);
351 }
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]));
357 failed = TRUE;
358 }
359 }
360 if (failed)
361 errln("MessageFormat failed test #6");
362 #endif
363 delete form;
364 }
365 }
366
sample()367 void TestMessageFormat::sample()
368 {
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.");
376 return;
377 }
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);
386 delete form;
387 }
388
testStaticFormat()389 void TestMessageFormat::testStaticFormat()
390 {
391 UErrorCode err = U_ZERO_ERROR;
392 Formattable arguments[] = {
393 (int32_t)7,
394 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
395 "a disturbance in the Force"
396 };
397
398 UnicodeString result;
399 result = MessageFormat::format(
400 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
401 arguments,
402 3,
403 result,
404 err);
405
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);
409 return;
410 }
411
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 );
418 }
419 }
420
421 /* When the default locale is tr, make sure that the pattern can still be parsed. */
TestTurkishCasing()422 void TestMessageFormat::TestTurkishCasing()
423 {
424 UErrorCode err = U_ZERO_ERROR;
425 Locale saveDefaultLocale;
426 Locale::setDefault( Locale("tr"), err );
427
428 Formattable arguments[] = {
429 (int32_t)7,
430 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
431 "a disturbance in the Force"
432 };
433
434 UnicodeString result;
435 result = MessageFormat::format(
436 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
437 arguments,
438 3,
439 result,
440 err);
441
442 if (U_FAILURE(err)) {
443 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err));
444 return;
445 }
446
447 const UnicodeString expected(
448 "At 12:20:00 on 8 08 1997, there was a disturbance in the Force on planet 7.", ""); // Google patch
449 if (result != expected) {
450 errln("TestTurkishCasing failed on test");
451 errln( UnicodeString(" Result: ") + result );
452 errln( UnicodeString(" Expected: ") + expected );
453 }
454 Locale::setDefault( saveDefaultLocale, err );
455 }
456
testSimpleFormat()457 void TestMessageFormat::testSimpleFormat(/* char* par */)
458 {
459 logln("running TestMessageFormat::testSimpleFormat");
460
461 UErrorCode err = U_ZERO_ERROR;
462
463 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
464 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
465 Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
466
467 MessageFormat* form = new MessageFormat(
468 "The disk \"{1}\" contains {0} file(s).", err);
469
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));
475 }
476
477 ignore.setField(FieldPosition::DONT_CARE);
478 string.remove();
479 form->format(testArgs2, 2, string, ignore, err);
480 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
481 logln(string);
482 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string + " - " + u_errorName(err));
483 }
484
485 ignore.setField(FieldPosition::DONT_CARE);
486 string.remove();
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));
490 }
491
492 delete form;
493 }
494
testMsgFormatChoice()495 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
496 {
497 logln("running TestMessageFormat::testMsgFormatChoice");
498
499 UErrorCode err = U_ZERO_ERROR;
500
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?
507
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");
514 }
515
516 ignore.setField(FieldPosition::DONT_CARE);
517 string.remove();
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");
522 }
523
524 ignore.setField(FieldPosition::DONT_CARE);
525 string.remove();
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));
530 }
531
532 delete form;
533 delete fileform;
534 }
535
536
testMsgFormatPlural()537 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
538 {
539 logln("running TestMessageFormat::testMsgFormatPlural");
540
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);
551 return;
552 }
553 Formattable testArgs1((int32_t)0);
554 FieldPosition ignore(FieldPosition::DONT_CARE);
555 UnicodeString numResult1;
556 mfNum->format(&testArgs1, 1, numResult1, ignore, err);
557
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);
565 delete mfNum;
566 return;
567 }
568 if ( numResult1 != argNameResult){
569 errln("TestMessageFormat::testMsgFormatPlural #1");
570 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
571 }
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."));
575 }
576 err = U_ZERO_ERROR;
577
578 delete mfNum;
579 delete mfAlpha;
580
581 MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err);
582 numResult1.remove();
583 Formattable testArgs2((int32_t)4);
584 mfNum2->format(&testArgs2, 1, numResult1, ignore, err);
585 MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err);
586 argNameResult.remove();
587 mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err);
588
589 if (U_FAILURE(err)) {
590 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
591 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err);
592 delete mfNum2;
593 return;
594 }
595 if ( numResult1 != argNameResult){
596 errln("TestMessageFormat::testMsgFormatPlural #2");
597 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
598 }
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."));
602 }
603
604 delete mfNum2;
605 delete mfAlpha2;
606
607 // nested formats
608 err = U_ZERO_ERROR;
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);
613 delete msgFmt;
614 return;
615 }
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");
621 }
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."));
625 }
626 delete msgFmt;
627 }
628
testApostropheInPluralAndSelect()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(),
634 errorCode);
635 if (U_FAILURE(errorCode)) {
636 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode));
637 return;
638 }
639 UnicodeString expected = UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
640 Formattable args[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
641 internalFormat(
642 &msgFmt, args, 2, expected,
643 "MessageFormat with apostrophes in plural/select arguments failed:\n");
644 }
645
internalFormat(MessageFormat * msgFmt,Formattable * args,int32_t numOfArgs,UnicodeString expected,const char * errMsg)646 void TestMessageFormat::internalFormat(MessageFormat* msgFmt ,
647 Formattable* args , int32_t numOfArgs ,
648 UnicodeString expected, const char* errMsg)
649 {
650 UnicodeString result;
651 FieldPosition ignore(FieldPosition::DONT_CARE);
652 UErrorCode status = U_ZERO_ERROR;
653
654 //Format with passed arguments
655 msgFmt->format( args , numOfArgs , result, ignore, status);
656 if (U_FAILURE(status)) {
657 dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) );
658 }
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");
663 dataerrln(err);
664 }
665 }
666
internalCreate(UnicodeString pattern,Locale locale,UErrorCode & status,char * errMsg)667 MessageFormat* TestMessageFormat::internalCreate(
668 UnicodeString pattern ,Locale locale ,UErrorCode &status , char* errMsg)
669 {
670 //Create the MessageFormat with simple SelectFormat
671 MessageFormat* msgFmt = new MessageFormat(pattern, locale, status);
672 if (U_FAILURE(status)) {
673 dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) );
674 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status);
675 return NULL;
676 }
677 return msgFmt;
678 }
679
testMsgFormatSelect()680 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
681 {
682 logln("running TestMessageFormat::testMsgFormatSelect");
683
684 UErrorCode err = U_ZERO_ERROR;
685 //French Pattern
686 UnicodeString t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
687
688 err = U_ZERO_ERROR;
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)) {
692 //Arguments
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."};
701 //Format
702 for( int i=0; i< 3; i++){
703 internalFormat( msgFmt1 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
704 }
705 }
706 delete msgFmt1;
707
708 //Quoted French Pattern
709 UnicodeString t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
710 err = U_ZERO_ERROR;
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)) {
714 //Arguments
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."};
723 //Format
724 for( int i=0; i< 3; i++){
725 internalFormat( msgFmt2 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
726 }
727 }
728 delete msgFmt2;
729
730 //English Pattern
731 UnicodeString t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
732 err = U_ZERO_ERROR;
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)) {
736 //Arguments
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."};
745 //Format
746 for( int i=0; i< 3; i++){
747 internalFormat( msgFmt3 , testArgs[i], 1, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
748 }
749 }
750 delete msgFmt3;
751
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 err = U_ZERO_ERROR;
756 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
757 MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4");
758 if (!U_FAILURE(err)) {
759 //Arguments
760 Formattable testArgs10[] = {"Kirti","female",(int32_t)6};
761 Formattable testArgs11[] = {"Kirti","female",100.100};
762 Formattable testArgs12[] = {"Kirti","other",(int32_t)6};
763 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
764 UnicodeString exp[] = {
765 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
766 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
767 "Kirti est all\\u00E9 \\u00E0 Paris."};
768 //Format
769 for( int i=0; i< 3; i++){
770 internalFormat( msgFmt4 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
771 }
772 }
773 delete msgFmt4;
774
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.");
777 err = U_ZERO_ERROR;
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)) {
781 //Arguments
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."};
792 //Format
793 for( int i=0; i< 4; i++){
794 internalFormat( msgFmt5 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
795 }
796 }
797 delete msgFmt5;
798
799 err = U_ZERO_ERROR;
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)) {
805 //Arguments
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."
839 };
840 //Format
841 for( int i=0; i< 14; i++){
842 internalFormat( msgFmt6 , testArgs[i], 4, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
843 }
844 }
845 delete msgFmt6;
846 }
847
848 //---------------------------------
849 // API Tests
850 //---------------------------------
851
testCopyConstructor()852 void TestMessageFormat::testCopyConstructor()
853 {
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);
859 if ( (*x == *y) &&
860 (*x != *z) &&
861 (*y != *z) )
862 logln("First test (operator ==): Passed!");
863 else {
864 errln("TestMessageFormat::testCopyConstructor failed #1");
865 logln("First test (operator ==): Failed!");
866 }
867 if ( ((*x == *y) && (*y == *x)) &&
868 ((*x != *z) && (*z != *x)) &&
869 ((*y != *z) && (*z != *y)) )
870 logln("Second test (equals): Passed!");
871 else {
872 errln("TestMessageFormat::testCopyConstructor failed #2");
873 logln("Second test (equals): Failed!");
874 }
875
876 delete x;
877 delete y;
878 delete z;
879 }
880
881
testAssignment()882 void TestMessageFormat::testAssignment()
883 {
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);
888 *y = *x;
889 if ( (*x == *y) &&
890 (*x != *z) &&
891 (*y != *z) )
892 logln("First test (operator ==): Passed!");
893 else {
894 errln( "TestMessageFormat::testAssignment failed #1");
895 logln("First test (operator ==): Failed!");
896 }
897 if ( ((*x == *y) && (*y == *x)) &&
898 ((*x != *z) && (*z != *x)) &&
899 ((*y != *z) && (*z != *y)) )
900 logln("Second test (equals): Passed!");
901 else {
902 errln("TestMessageFormat::testAssignment failed #2");
903 logln("Second test (equals): Failed!");
904 }
905
906 delete x;
907 delete y;
908 delete z;
909 }
910
testClone()911 void TestMessageFormat::testClone()
912 {
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();
918 if ( (*x == *y) &&
919 (*x != *z) &&
920 (*y != *z) )
921 logln("First test (operator ==): Passed!");
922 else {
923 errln("TestMessageFormat::testClone failed #1");
924 logln("First test (operator ==): Failed!");
925 }
926 if ( ((*x == *y) && (*y == *x)) &&
927 ((*x != *z) && (*z != *x)) &&
928 ((*y != *z) && (*z != *y)) )
929 logln("Second test (equals): Passed!");
930 else {
931 errln("TestMessageFormat::testClone failed #2");
932 logln("Second test (equals): Failed!");
933 }
934
935 delete x;
936 delete y;
937 delete z;
938 }
939
testEquals()940 void TestMessageFormat::testEquals()
941 {
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);
945 if (!(x == y)) {
946 errln( "TestMessageFormat::testEquals failed #1");
947 logln("First test (operator ==): Failed!");
948 }
949
950 }
951
testNotEquals()952 void TestMessageFormat::testNotEquals()
953 {
954 UErrorCode success = U_ZERO_ERROR;
955 MessageFormat x("There are {0} files on {1}", success);
956 MessageFormat y(x);
957 y.setLocale(Locale("fr"));
958 if (!(x != y)) {
959 errln( "TestMessageFormat::testEquals failed #1");
960 logln("First test (operator !=): Failed!");
961 }
962 y = x;
963 y.applyPattern("There are {0} files on {1} the disk", success);
964 if (!(x != y)) {
965 errln( "TestMessageFormat::testEquals failed #1");
966 logln("Second test (operator !=): Failed!");
967 }
968 }
969
970
testSetLocale()971 void TestMessageFormat::testSetLocale()
972 {
973 UErrorCode err = U_ZERO_ERROR;
974 GregorianCalendar cal(err);
975 Formattable arguments[] = {
976 456.83,
977 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
978 "deposit"
979 };
980
981 UnicodeString result;
982
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 += ".";
999
1000 MessageFormat msg( formatStr, err);
1001 result = "";
1002 FieldPosition pos(0);
1003 result = msg.format(
1004 arguments,
1005 3,
1006 result,
1007 pos,
1008 err);
1009
1010 logln(result);
1011 if (result != compareStrEng) {
1012 dataerrln("*** MSG format err. - %s", u_errorName(err));
1013 }
1014
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;
1020 }
1021
1022 msg.setLocale(Locale::getGerman());
1023
1024 if (msg.getLocale() != Locale::getGerman()) {
1025 errln("*** MSG getLocal err.");
1026 getLocale_ok = FALSE;
1027 }
1028
1029 msg.applyPattern( formatStr, err);
1030
1031 pos.setField(0);
1032 result = "";
1033 result = msg.format(
1034 arguments,
1035 3,
1036 result,
1037 pos,
1038 err);
1039
1040 logln(result);
1041 if (result == compareStrGer) {
1042 logln("MSG setLocale tested.");
1043 }else{
1044 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err));
1045 }
1046
1047 if (getLocale_ok) {
1048 logln("MSG getLocale tested.");
1049 }
1050 }
1051
testFormat()1052 void TestMessageFormat::testFormat()
1053 {
1054 UErrorCode err = U_ZERO_ERROR;
1055 GregorianCalendar cal(err);
1056
1057 const Formattable ftarray[] =
1058 {
1059 Formattable( UDate(8.71068e+011), Formattable::kIsDate )
1060 };
1061 const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable);
1062 Formattable ft_arr( ftarray, ft_cnt );
1063
1064 Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
1065
1066 UnicodeString result;
1067
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.";
1071
1072 err = U_ZERO_ERROR;
1073 MessageFormat msg( formatStr, err);
1074 FieldPosition fp(0);
1075
1076 result = "";
1077 fp = 0;
1078 result = msg.format(
1079 *fmt,
1080 result,
1081 //FieldPosition(0),
1082 fp,
1083 err);
1084
1085 if (err != U_ILLEGAL_ARGUMENT_ERROR) {
1086 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err));
1087 }
1088 err = U_ZERO_ERROR;
1089
1090 result = "";
1091 fp = 0;
1092 result = msg.format(
1093 ft_arr,
1094 result,
1095 //FieldPosition(0),
1096 fp,
1097 err);
1098
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));
1103 }else{
1104 logln("MSG format( Formattable&, ... ) tested.");
1105 }
1106
1107 delete fmt;
1108
1109 }
1110
testParse()1111 void TestMessageFormat::testParse()
1112 {
1113 UErrorCode err = U_ZERO_ERROR;
1114 int32_t count;
1115 UnicodeString msgFormatString = "{0} =sep= {1}";
1116 MessageFormat msg( msgFormatString, err);
1117 UnicodeString source = "abc =sep= def";
1118 UnicodeString tmp1, tmp2;
1119
1120 Formattable* fmt_arr = msg.parse( source, count, err );
1121 if (U_FAILURE(err) || (!fmt_arr)) {
1122 errln("*** MSG parse (ustring, count, err) error.");
1123 }else{
1124 logln("MSG parse -- count: %d", count);
1125 if (count != 2) {
1126 errln("*** MSG parse (ustring, count, err) count err.");
1127 }else{
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.");
1133 }else{
1134 errln("*** MSG parse (ustring, count, err) result err.");
1135 }
1136 }
1137 }
1138 delete[] fmt_arr;
1139
1140 ParsePosition pp(0);
1141
1142 fmt_arr = msg.parse( source, pp, count );
1143 if ((pp == 0) || (!fmt_arr)) {
1144 errln("*** MSG parse (ustring, parsepos., count) error.");
1145 }else{
1146 logln("MSG parse -- count: %d", count);
1147 if (count != 2) {
1148 errln("*** MSG parse (ustring, parsepos., count) count err.");
1149 }else{
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.");
1155 }else{
1156 errln("*** MSG parse (ustring, parsepos., count) result err.");
1157 }
1158 }
1159 }
1160 delete[] fmt_arr;
1161
1162 pp = 0;
1163 Formattable fmta;
1164
1165 msg.parseObject( source, fmta, pp );
1166 if (pp == 0) {
1167 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1168 }else{
1169 logln("MSG parse -- count: %d", count);
1170 fmta.getArray(count);
1171 if (count != 2) {
1172 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1173 }else{
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.");
1179 }else{
1180 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1181 }
1182 }
1183 }
1184 }
1185
1186
testAdopt()1187 void TestMessageFormat::testAdopt()
1188 {
1189 UErrorCode err = U_ZERO_ERROR;
1190
1191 UnicodeString formatStr("{0,date},{1},{2,number}", "");
1192 UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
1193 err = U_ZERO_ERROR;
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));
1198 return;
1199 }
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;
1205 int32_t countAct;
1206 const Format* a;
1207 const Format* b;
1208 UnicodeString patCmp;
1209 UnicodeString patAct;
1210 Format** formatsToAdopt;
1211
1212 if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
1213 dataerrln("Error getting Formats");
1214 return;
1215 }
1216
1217 int32_t i;
1218
1219 for (i = 0; i < count; i++) {
1220 a = formats[i];
1221 b = formatsCmp[i];
1222 if ((a != NULL) && (b != NULL)) {
1223 if (*a != *b) {
1224 errln("a != b");
1225 return;
1226 }
1227 }else if ((a != NULL) || (b != NULL)) {
1228 errln("(a != NULL) || (b != NULL)");
1229 return;
1230 }
1231 }
1232
1233 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1234 int32_t countChg;
1235 formatsChg = msg.getFormats(countChg); // tested function
1236 if (!formatsChg || (countChg != count)) {
1237 errln("Error getting Formats");
1238 return;
1239 }
1240
1241 UBool diff;
1242 diff = TRUE;
1243 for (i = 0; i < count; i++) {
1244 a = formatsChg[i];
1245 b = formatsCmp[i];
1246 if ((a != NULL) && (b != NULL)) {
1247 if (*a == *b) {
1248 logln("formatsChg == formatsCmp at index %d", i);
1249 diff = FALSE;
1250 }
1251 }
1252 }
1253 if (!diff) {
1254 errln("*** MSG getFormats diff err.");
1255 return;
1256 }
1257
1258 logln("MSG getFormats tested.");
1259
1260 msg.setFormats( formatsCmp, countCmp ); //tested function
1261
1262 formatsAct = msg.getFormats(countAct);
1263 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1264 errln("Error getting Formats");
1265 return;
1266 }
1267
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.");
1274 }
1275
1276 for (i = 0; i < countAct; i++) {
1277 a = formatsAct[i];
1278 b = formatsCmp[i];
1279 if ((a != NULL) && (b != NULL)) {
1280 if (*a != *b) {
1281 logln("formatsAct != formatsCmp at index %d", i);
1282 errln("a != b");
1283 return;
1284 }
1285 }else if ((a != NULL) || (b != NULL)) {
1286 errln("(a != NULL) || (b != NULL)");
1287 return;
1288 }
1289 }
1290 logln("MSG setFormats tested.");
1291
1292 //----
1293
1294 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1295
1296 formatsToAdopt = new Format* [countCmp];
1297 if (!formatsToAdopt) {
1298 errln("memory allocation error");
1299 return;
1300 }
1301
1302 for (i = 0; i < countCmp; i++) {
1303 if (formatsCmp[i] == NULL) {
1304 formatsToAdopt[i] = NULL;
1305 }else{
1306 formatsToAdopt[i] = formatsCmp[i]->clone();
1307 if (!formatsToAdopt[i]) {
1308 errln("Can't clone format at index %d", i);
1309 return;
1310 }
1311 }
1312 }
1313 msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
1314 delete[] formatsToAdopt;
1315
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()));
1319
1320 formatsAct = msg.getFormats(countAct);
1321 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1322 errln("Error getting Formats");
1323 return;
1324 }
1325
1326 for (i = 0; i < countAct; i++) {
1327 a = formatsAct[i];
1328 b = formatsCmp[i];
1329 if ((a != NULL) && (b != NULL)) {
1330 if (*a != *b) {
1331 errln("a != b");
1332 return;
1333 }
1334 }else if ((a != NULL) || (b != NULL)) {
1335 errln("(a != NULL) || (b != NULL)");
1336 return;
1337 }
1338 }
1339 logln("MSG adoptFormats tested.");
1340
1341 //---- adoptFormat
1342
1343 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1344
1345 formatsToAdopt = new Format* [countCmp];
1346 if (!formatsToAdopt) {
1347 errln("memory allocation error");
1348 return;
1349 }
1350
1351 for (i = 0; i < countCmp; i++) {
1352 if (formatsCmp[i] == NULL) {
1353 formatsToAdopt[i] = NULL;
1354 }else{
1355 formatsToAdopt[i] = formatsCmp[i]->clone();
1356 if (!formatsToAdopt[i]) {
1357 errln("Can't clone format at index %d", i);
1358 return;
1359 }
1360 }
1361 }
1362
1363 for ( i = 0; i < countCmp; i++ ) {
1364 msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
1365 }
1366 delete[] formatsToAdopt; // array itself not needed in this case;
1367
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()));
1371
1372 formatsAct = msg.getFormats(countAct);
1373 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1374 errln("Error getting Formats");
1375 return;
1376 }
1377
1378 for (i = 0; i < countAct; i++) {
1379 a = formatsAct[i];
1380 b = formatsCmp[i];
1381 if ((a != NULL) && (b != NULL)) {
1382 if (*a != *b) {
1383 errln("a != b");
1384 return;
1385 }
1386 }else if ((a != NULL) || (b != NULL)) {
1387 errln("(a != NULL) || (b != NULL)");
1388 return;
1389 }
1390 }
1391 logln("MSG adoptFormat tested.");
1392 }
1393
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*.
_testCopyConstructor2()1400 static void _testCopyConstructor2()
1401 {
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 );
1409
1410 MessageFormat* fmt1 = new MessageFormat( formatStr, status );
1411 MessageFormat* fmt2 = NULL;
1412 MessageFormat* fmt3 = NULL;
1413 MessageFormat* fmt4 = NULL;
1414
1415 if (fmt1 == NULL) {
1416 it_err("testCopyConstructor2: (fmt1 != NULL)");
1417 goto cleanup;
1418 }
1419
1420 fmt2 = new MessageFormat( *fmt1 );
1421 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1422
1423 if (fmt2 == NULL) {
1424 it_err("testCopyConstructor2: (fmt2 != NULL)");
1425 goto cleanup;
1426 }
1427
1428 fmt3 = (MessageFormat*) fmt1->clone();
1429 fmt4 = (MessageFormat*) fmt2->clone();
1430
1431 if (fmt3 == NULL) {
1432 it_err("testCopyConstructor2: (fmt3 != NULL)");
1433 goto cleanup;
1434 }
1435 if (fmt4 == NULL) {
1436 it_err("testCopyConstructor2: (fmt4 != NULL)");
1437 goto cleanup;
1438 }
1439
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 );
1444
1445 cleanup:
1446 delete fmt1;
1447 delete fmt2;
1448 delete fmt3;
1449 delete fmt4;
1450 }
1451
testCopyConstructor2()1452 void TestMessageFormat::testCopyConstructor2() {
1453 _testCopyConstructor2();
1454 }
1455
1456 /**
1457 * Verify that MessageFormat accomodates more than 10 arguments and
1458 * more than 10 subformats.
1459 */
TestUnlimitedArgsAndSubformats()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));
1472 return;
1473 }
1474
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"),
1488 };
1489 const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]);
1490 Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
1491
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) {
1503 logln(result);
1504 } else {
1505 errln((UnicodeString)"FAIL: Got " + result +
1506 ", expected " + expected);
1507 }
1508 }
1509
1510 // test RBNF extensions to message format
TestRBNF(void)1511 void TestMessageFormat::TestRBNF(void) {
1512 // WARNING: this depends on the RBNF formats for en_US
1513 Locale locale("en", "US", "");
1514
1515 UErrorCode ec = U_ZERO_ERROR;
1516
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",
1521 };
1522 int32_t values_count = sizeof(values)/sizeof(values[0]);
1523
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.",
1529 "Searching this file will take {0,duration} to complete.",
1530 "Searching this file will take {0,duration,%with-words} to complete.",
1531 };
1532 int32_t formats_count = sizeof(formats)/sizeof(formats[0]);
1533
1534 Formattable args[1];
1535
1536 NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
1537 if (U_FAILURE(ec)) {
1538 dataerrln("Error calling NumberFormat::createInstance()");
1539 return;
1540 }
1541
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] + "'");
1545
1546 for (int j = 0; j < values_count; ++j) {
1547 ec = U_ZERO_ERROR;
1548 numFmt->parse(values[j], args[0], ec);
1549 if (U_FAILURE(ec)) {
1550 errln((UnicodeString)"Failed to parse test argument " + values[j]);
1551 } else {
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));
1556
1557 int32_t count = 0;
1558 Formattable* parseResult = fmt->parse(result, count, ec);
1559 if (count != 1) {
1560 errln((UnicodeString)"parse returned " + count + " args");
1561 } else if (parseResult[0] != args[0]) {
1562 errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
1563 }
1564 delete []parseResult;
1565 }
1566 }
1567 delete fmt;
1568 }
1569 delete numFmt;
1570 }
1571
GetPatternAndSkipSyntax(const MessagePattern & pattern)1572 UnicodeString TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern& pattern) {
1573 UnicodeString us(pattern.getPatternString());
1574 int count = pattern.countParts();
1575 for (int i = count; i > 0;) {
1576 const MessagePattern::Part& part = pattern.getPart(--i);
1577 if (part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1578 us.remove(part.getIndex(), part.getLimit() - part.getIndex());
1579 }
1580 }
1581 return us;
1582 }
1583
TestApostropheMode()1584 void TestMessageFormat::TestApostropheMode() {
1585 UErrorCode status = U_ZERO_ERROR;
1586 MessagePattern *ado_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL, status);
1587 MessagePattern *adr_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED, status);
1588 if (ado_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1589 errln("wrong value from ado_mp->getApostropheMode().");
1590 }
1591 if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1592 errln("wrong value from adr_mp->getApostropheMode().");
1593 }
1594
1595
1596 UnicodeString tuples[] = {
1597 // Desired output
1598 // DOUBLE_OPTIONAL pattern
1599 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1600 "I see {many}", "I see '{many}'", "",
1601 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1602 "I dont know", "I dont know", "I don't know",
1603 "I don't know", "I don't know", "I don''t know",
1604 "I don't know", "I don''t know", "I don''t know"
1605 };
1606 int32_t tuples_count = UPRV_LENGTHOF(tuples);
1607
1608 for (int i = 0; i < tuples_count; i += 3) {
1609 UnicodeString& desired = tuples[i];
1610 UnicodeString& ado_pattern = tuples[i + 1];
1611 UErrorCode status = U_ZERO_ERROR;
1612 assertEquals("DOUBLE_OPTIONAL failure",
1613 desired,
1614 GetPatternAndSkipSyntax(ado_mp->parse(ado_pattern, NULL, status)));
1615 UnicodeString& adr_pattern = tuples[i + 2].isEmpty() ? ado_pattern : tuples[i + 2];
1616 assertEquals("DOUBLE_REQUIRED failure", desired,
1617 GetPatternAndSkipSyntax(adr_mp->parse(adr_pattern, NULL, status)));
1618 }
1619 delete adr_mp;
1620 delete ado_mp;
1621 }
1622
1623
1624 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
TestCompatibleApostrophe()1625 void TestMessageFormat::TestCompatibleApostrophe() {
1626 // Message with choice argument which does not contain another argument.
1627 // The JDK performs only one apostrophe-quoting pass on this pattern.
1628 UnicodeString pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
1629
1630 UErrorCode ec = U_ZERO_ERROR;
1631 MessageFormat compMsg("", Locale::getUS(), ec);
1632 compMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, ec);
1633 if (compMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1634 errln("wrong value from compMsg.getApostropheMode().");
1635 }
1636
1637 MessageFormat icuMsg("", Locale::getUS(), ec);
1638 icuMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_OPTIONAL, NULL, ec);
1639 if (icuMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1640 errln("wrong value from icuMsg.getApostropheMode().");
1641 }
1642
1643 Formattable zero0[] = { (int32_t)0 };
1644 FieldPosition fieldpos(0);
1645 UnicodeString buffer1, buffer2;
1646 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1647 "ab12'3'4''.yz",
1648 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1649 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1650 "ab1'2'3''4''.yz",
1651 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1652
1653 // Message with choice argument which contains a nested simple argument.
1654 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1655 buffer1.remove();
1656 buffer2.remove();
1657 pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1658 compMsg.applyPattern(pattern, ec);
1659 icuMsg.applyPattern(pattern, ec);
1660 if (U_FAILURE(ec)) {
1661 dataerrln("Unable to applyPattern - %s", u_errorName(ec));
1662 } else {
1663 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1664 "ab1234'.0xyz",
1665 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1666 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1667 "ab1'2'3''4''.#x0yz",
1668 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1669 }
1670
1671 // This part is copied over from Java tests but cannot be properly tested here
1672 // because we do not have a live reference implementation with JDK behavior.
1673 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1674 /*
1675 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1676 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1677 "12'3'4''.",
1678 choice.format(0));
1679 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1680 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1681 "12'3'4''.{0,number,#x}",
1682 choice.format(0));
1683 */
1684 }
1685
testAutoQuoteApostrophe(void)1686 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1687 const char* patterns[] = { // pattern, expected pattern
1688 "'", "''",
1689 "''", "''",
1690 "'{", "'{'",
1691 "' {", "'' {",
1692 "'a", "''a",
1693 "'{'a", "'{'a",
1694 "'{a'", "'{a'",
1695 "'{}", "'{}'",
1696 "{'", "{'",
1697 "{'a", "{'a",
1698 "{'a{}'a}'a", "{'a{}'a}''a",
1699 "'}'", "'}'",
1700 "'} '{'}'", "'} '{'}''",
1701 "'} {{{''", "'} {{{'''",
1702 };
1703 int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
1704
1705 for (int i = 0; i < pattern_count; i += 2) {
1706 UErrorCode status = U_ZERO_ERROR;
1707 UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
1708 UnicodeString target(patterns[i+1]);
1709 if (target != result) {
1710 const int BUF2_LEN = 64;
1711 char buf[256];
1712 char buf2[BUF2_LEN];
1713 int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
1714 if (len >= BUF2_LEN) {
1715 buf2[BUF2_LEN-1] = 0;
1716 }
1717 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1718 errln(buf);
1719 }
1720 }
1721 }
1722
testCoverage(void)1723 void TestMessageFormat::testCoverage(void) {
1724 UErrorCode status = U_ZERO_ERROR;
1725 UnicodeString testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1726 MessageFormat *msgfmt = new MessageFormat(testformat, Locale("fr"), status);
1727 if (msgfmt == NULL || U_FAILURE(status)) {
1728 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status));
1729 return;
1730 }
1731 if (!msgfmt->usesNamedArguments()) {
1732 errln("FAIL: Unable to detect usage of named arguments.");
1733 }
1734 const double limit[] = {0.0, 1.0, 2.0};
1735 const UnicodeString formats[] = {"0.0<=Arg<1.0",
1736 "1.0<=Arg<2.0",
1737 "2.0<-Arg"};
1738 ChoiceFormat cf(limit, formats, 3);
1739
1740 msgfmt->setFormat("set", cf, status);
1741
1742 StringEnumeration *en = msgfmt->getFormatNames(status);
1743 if (en == NULL || U_FAILURE(status)) {
1744 errln("FAIL: Unable to get format names enumeration.");
1745 } else {
1746 int32_t count = 0;
1747 en->reset(status);
1748 count = en->count(status);
1749 if (U_FAILURE(status)) {
1750 errln("FAIL: Unable to get format name enumeration count.");
1751 } else {
1752 for (int32_t i = 0; i < count; i++) {
1753 en->snext(status);
1754 if (U_FAILURE(status)) {
1755 errln("FAIL: Error enumerating through names.");
1756 break;
1757 }
1758 }
1759 }
1760 }
1761
1762 // adoptFormat() takes ownership of the input Format object.
1763 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1764 Format *cfClone = cf.clone();
1765 msgfmt->adoptFormat("adopt", cfClone, status);
1766
1767 delete en;
1768 delete msgfmt;
1769
1770 msgfmt = new MessageFormat("'", status);
1771 if (msgfmt == NULL || U_FAILURE(status)) {
1772 errln("FAIL: Unable to create MessageFormat.");
1773 return;
1774 }
1775 if (msgfmt->usesNamedArguments()) {
1776 errln("FAIL: Unable to detect usage of named arguments.");
1777 }
1778
1779 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1780 // on a MessageFormat without named arguments.
1781 msgfmt->setFormat("formatName", cf, status);
1782 if (U_FAILURE(status)) {
1783 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1784 }
1785 status = U_ZERO_ERROR;
1786 en = msgfmt->getFormatNames(status);
1787 if (U_FAILURE(status)) {
1788 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1789 }
1790
1791 delete en;
1792 delete msgfmt;
1793 }
1794
testGetFormatNames()1795 void TestMessageFormat::testGetFormatNames() {
1796 IcuTestErrorCode errorCode(*this, "testGetFormatNames");
1797 MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode);
1798 if(errorCode.logDataIfFailureAndReset("MessageFormat() failed")) {
1799 return;
1800 }
1801 LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode));
1802 if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1803 return;
1804 }
1805 const UnicodeString *name;
1806 name = names->snext(errorCode);
1807 if (name == NULL || errorCode.isFailure()) {
1808 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName());
1809 errorCode.reset();
1810 return;
1811 }
1812 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) {
1813 return;
1814 }
1815 name = names->snext(errorCode);
1816 if (name == NULL || errorCode.isFailure()) {
1817 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName());
1818 errorCode.reset();
1819 return;
1820 }
1821 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) {
1822 return;
1823 }
1824 name = names->snext(errorCode);
1825 if (name == NULL || errorCode.isFailure()) {
1826 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName());
1827 errorCode.reset();
1828 return;
1829 }
1830 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) {
1831 return;
1832 }
1833 name = names->snext(errorCode);
1834 if (name != NULL) {
1835 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name);
1836 return;
1837 }
1838 }
1839
TestTrimArgumentName()1840 void TestMessageFormat::TestTrimArgumentName() {
1841 // ICU 4.8 allows and ignores white space around argument names and numbers.
1842 IcuTestErrorCode errorCode(*this, "TestTrimArgumentName");
1843 MessageFormat m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode);
1844 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1845 return;
1846 }
1847 Formattable args[1] = { (int32_t)2 };
1848 FieldPosition ignore(0);
1849 UnicodeString result;
1850 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1851 m.format(args, 1, result, ignore, errorCode));
1852
1853 m.applyPattern("x { _oOo_ , number , integer } y", errorCode);
1854 UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_");
1855 args[0].setLong(3);
1856 result.remove();
1857 assertEquals("trim-named-arg format() failed", "x 3 y",
1858 m.format(&argName, args, 1, result, errorCode));
1859 }
1860
TestSelectOrdinal()1861 void TestMessageFormat::TestSelectOrdinal() {
1862 IcuTestErrorCode errorCode(*this, "TestSelectOrdinal");
1863 // Test plural & ordinal together,
1864 // to make sure that we get the correct cached PluralSelector for each.
1865 MessageFormat m(
1866 "{0,plural,one{1 file}other{# files}}, "
1867 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
1868 Locale::getEnglish(), errorCode);
1869 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1870 return;
1871 }
1872 Formattable args[1] = { (int32_t)21 };
1873 FieldPosition ignore(0);
1874 UnicodeString result;
1875 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file",
1876 m.format(args, 1, result, ignore, errorCode), TRUE);
1877
1878 args[0].setLong(2);
1879 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1880 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1881
1882 args[0].setLong(1);
1883 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1884 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1885
1886 args[0].setLong(3);
1887 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1888 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1889
1890 errorCode.logDataIfFailureAndReset("");
1891 }
1892
TestDecimals()1893 void TestMessageFormat::TestDecimals() {
1894 IcuTestErrorCode errorCode(*this, "TestDecimals");
1895 // Simple number replacement.
1896 MessageFormat m(
1897 "{0,plural,one{one meter}other{# meters}}",
1898 Locale::getEnglish(), errorCode);
1899 Formattable args[1] = { (int32_t)1 };
1900 FieldPosition ignore;
1901 UnicodeString result;
1902 assertEquals("simple format(1)", "one meter",
1903 m.format(args, 1, result, ignore, errorCode), TRUE);
1904
1905 args[0] = (double)1.5;
1906 result.remove();
1907 assertEquals("simple format(1.5)", "1.5 meters",
1908 m.format(args, 1, result, ignore, errorCode), TRUE);
1909
1910 // Simple but explicit.
1911 MessageFormat m0(
1912 "{0,plural,one{one meter}other{{0} meters}}",
1913 Locale::getEnglish(), errorCode);
1914 args[0] = (int32_t)1;
1915 result.remove();
1916 assertEquals("explicit format(1)", "one meter",
1917 m0.format(args, 1, result, ignore, errorCode), TRUE);
1918
1919 args[0] = (double)1.5;
1920 result.remove();
1921 assertEquals("explicit format(1.5)", "1.5 meters",
1922 m0.format(args, 1, result, ignore, errorCode), TRUE);
1923
1924 // With offset and specific simple format with optional decimals.
1925 MessageFormat m1(
1926 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1927 Locale::getEnglish(), errorCode);
1928 args[0] = (int32_t)1;
1929 result.remove();
1930 assertEquals("offset format(1)", "01 meters",
1931 m1.format(args, 1, result, ignore, errorCode), TRUE);
1932
1933 args[0] = (int32_t)2;
1934 result.remove();
1935 assertEquals("offset format(1)", "another meter",
1936 m1.format(args, 1, result, ignore, errorCode), TRUE);
1937
1938 args[0] = (double)2.5;
1939 result.remove();
1940 assertEquals("offset format(1)", "02.5 meters",
1941 m1.format(args, 1, result, ignore, errorCode), TRUE);
1942
1943 // With offset and specific simple format with forced decimals.
1944 MessageFormat m2(
1945 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1946 Locale::getEnglish(), errorCode);
1947 args[0] = (int32_t)1;
1948 result.remove();
1949 assertEquals("offset-decimals format(1)", "1.0 meters",
1950 m2.format(args, 1, result, ignore, errorCode), TRUE);
1951
1952 args[0] = (int32_t)2;
1953 result.remove();
1954 assertEquals("offset-decimals format(1)", "2.0 meters",
1955 m2.format(args, 1, result, ignore, errorCode), TRUE);
1956
1957 args[0] = (double)2.5;
1958 result.remove();
1959 assertEquals("offset-decimals format(1)", "2.5 meters",
1960 m2.format(args, 1, result, ignore, errorCode), TRUE);
1961 errorCode.reset();
1962 }
1963
1964 #endif /* #if !UCONFIG_NO_FORMATTING */
1965