]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tmsgfmt.cpp
ICU-551.51.tar.gz
[apple/icu.git] / icuSources / test / intltest / tmsgfmt.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2014, 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
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
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
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
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
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
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
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. */
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.", "");
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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*.
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
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 */
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
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.", // 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.",
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 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1558 int32_t count = 0;
1559 Formattable* parseResult = fmt->parse(result, count, ec);
1560 if (count != 1) {
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]));
1564 }
1565 delete []parseResult;
1566 }
1567 }
1568 }
1569 delete fmt;
1570 }
1571 delete numFmt;
1572 }
1573
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());
1581 }
1582 }
1583 return us;
1584 }
1585
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().");
1592 }
1593 if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1594 errln("wrong value from adr_mp->getApostropheMode().");
1595 }
1596
1597
1598 UnicodeString tuples[] = {
1599 // Desired output
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"
1607 };
1608 int32_t tuples_count = UPRV_LENGTHOF(tuples);
1609
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",
1615 desired,
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)));
1620 }
1621 delete adr_mp;
1622 delete ado_mp;
1623 }
1624
1625
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";
1631
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().");
1637 }
1638
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().");
1643 }
1644
1645 Formattable zero0[] = { (int32_t)0 };
1646 FieldPosition fieldpos(0);
1647 UnicodeString buffer1, buffer2;
1648 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1649 "ab12'3'4''.yz",
1650 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1651 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1652 "ab1'2'3''4''.yz",
1653 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1654
1655 // Message with choice argument which contains a nested simple argument.
1656 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1657 buffer1.remove();
1658 buffer2.remove();
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));
1664 } else {
1665 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1666 "ab1234'.0xyz",
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));
1671 }
1672
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.
1676 /*
1677 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1678 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1679 "12'3'4''.",
1680 choice.format(0));
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}",
1684 choice.format(0));
1685 */
1686 }
1687
1688 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1689 const char* patterns[] = { // pattern, expected pattern
1690 "'", "''",
1691 "''", "''",
1692 "'{", "'{'",
1693 "' {", "'' {",
1694 "'a", "''a",
1695 "'{'a", "'{'a",
1696 "'{a'", "'{a'",
1697 "'{}", "'{}'",
1698 "{'", "{'",
1699 "{'a", "{'a",
1700 "{'a{}'a}'a", "{'a{}'a}''a",
1701 "'}'", "'}'",
1702 "'} '{'}'", "'} '{'}''",
1703 "'} {{{''", "'} {{{'''",
1704 };
1705 int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
1706
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;
1713 char buf[256];
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;
1718 }
1719 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1720 errln(buf);
1721 }
1722 }
1723 }
1724
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));
1731 return;
1732 }
1733 if (!msgfmt->usesNamedArguments()) {
1734 errln("FAIL: Unable to detect usage of named arguments.");
1735 }
1736 const double limit[] = {0.0, 1.0, 2.0};
1737 const UnicodeString formats[] = {"0.0<=Arg<1.0",
1738 "1.0<=Arg<2.0",
1739 "2.0<-Arg"};
1740 ChoiceFormat cf(limit, formats, 3);
1741
1742 msgfmt->setFormat("set", cf, status);
1743
1744 StringEnumeration *en = msgfmt->getFormatNames(status);
1745 if (en == NULL || U_FAILURE(status)) {
1746 errln("FAIL: Unable to get format names enumeration.");
1747 } else {
1748 int32_t count = 0;
1749 en->reset(status);
1750 count = en->count(status);
1751 if (U_FAILURE(status)) {
1752 errln("FAIL: Unable to get format name enumeration count.");
1753 } else {
1754 for (int32_t i = 0; i < count; i++) {
1755 en->snext(status);
1756 if (U_FAILURE(status)) {
1757 errln("FAIL: Error enumerating through names.");
1758 break;
1759 }
1760 }
1761 }
1762 }
1763
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);
1768
1769 delete en;
1770 delete msgfmt;
1771
1772 msgfmt = new MessageFormat("'", status);
1773 if (msgfmt == NULL || U_FAILURE(status)) {
1774 errln("FAIL: Unable to create MessageFormat.");
1775 return;
1776 }
1777 if (msgfmt->usesNamedArguments()) {
1778 errln("FAIL: Unable to detect usage of named arguments.");
1779 }
1780
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.");
1786 }
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.");
1791 }
1792
1793 delete en;
1794 delete msgfmt;
1795 }
1796
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")) {
1801 return;
1802 }
1803 LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode));
1804 if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1805 return;
1806 }
1807 const UnicodeString *name;
1808 name = names->snext(errorCode);
1809 if (name == NULL || errorCode.isFailure()) {
1810 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName());
1811 errorCode.reset();
1812 return;
1813 }
1814 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) {
1815 return;
1816 }
1817 name = names->snext(errorCode);
1818 if (name == NULL || errorCode.isFailure()) {
1819 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName());
1820 errorCode.reset();
1821 return;
1822 }
1823 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) {
1824 return;
1825 }
1826 name = names->snext(errorCode);
1827 if (name == NULL || errorCode.isFailure()) {
1828 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName());
1829 errorCode.reset();
1830 return;
1831 }
1832 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) {
1833 return;
1834 }
1835 name = names->snext(errorCode);
1836 if (name != NULL) {
1837 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name);
1838 return;
1839 }
1840 }
1841
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")) {
1847 return;
1848 }
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));
1854
1855 m.applyPattern("x { _oOo_ , number , integer } y", errorCode);
1856 UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_");
1857 args[0].setLong(3);
1858 result.remove();
1859 assertEquals("trim-named-arg format() failed", "x 3 y",
1860 m.format(&argName, args, 1, result, errorCode));
1861 }
1862
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.
1867 MessageFormat m(
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")) {
1872 return;
1873 }
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);
1879
1880 args[0].setLong(2);
1881 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1882 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1883
1884 args[0].setLong(1);
1885 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1886 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1887
1888 args[0].setLong(3);
1889 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1890 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1891
1892 errorCode.logDataIfFailureAndReset("");
1893 }
1894
1895 void TestMessageFormat::TestDecimals() {
1896 IcuTestErrorCode errorCode(*this, "TestDecimals");
1897 // Simple number replacement.
1898 MessageFormat m(
1899 "{0,plural,one{one meter}other{# meters}}",
1900 Locale::getEnglish(), errorCode);
1901 Formattable args[1] = { (int32_t)1 };
1902 FieldPosition ignore;
1903 UnicodeString result;
1904 assertEquals("simple format(1)", "one meter",
1905 m.format(args, 1, result, ignore, errorCode), TRUE);
1906
1907 args[0] = (double)1.5;
1908 result.remove();
1909 assertEquals("simple format(1.5)", "1.5 meters",
1910 m.format(args, 1, result, ignore, errorCode), TRUE);
1911
1912 // Simple but explicit.
1913 MessageFormat m0(
1914 "{0,plural,one{one meter}other{{0} meters}}",
1915 Locale::getEnglish(), errorCode);
1916 args[0] = (int32_t)1;
1917 result.remove();
1918 assertEquals("explicit format(1)", "one meter",
1919 m0.format(args, 1, result, ignore, errorCode), TRUE);
1920
1921 args[0] = (double)1.5;
1922 result.remove();
1923 assertEquals("explicit format(1.5)", "1.5 meters",
1924 m0.format(args, 1, result, ignore, errorCode), TRUE);
1925
1926 // With offset and specific simple format with optional decimals.
1927 MessageFormat m1(
1928 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1929 Locale::getEnglish(), errorCode);
1930 args[0] = (int32_t)1;
1931 result.remove();
1932 assertEquals("offset format(1)", "01 meters",
1933 m1.format(args, 1, result, ignore, errorCode), TRUE);
1934
1935 args[0] = (int32_t)2;
1936 result.remove();
1937 assertEquals("offset format(1)", "another meter",
1938 m1.format(args, 1, result, ignore, errorCode), TRUE);
1939
1940 args[0] = (double)2.5;
1941 result.remove();
1942 assertEquals("offset format(1)", "02.5 meters",
1943 m1.format(args, 1, result, ignore, errorCode), TRUE);
1944
1945 // With offset and specific simple format with forced decimals.
1946 MessageFormat m2(
1947 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1948 Locale::getEnglish(), errorCode);
1949 args[0] = (int32_t)1;
1950 result.remove();
1951 assertEquals("offset-decimals format(1)", "1.0 meters",
1952 m2.format(args, 1, result, ignore, errorCode), TRUE);
1953
1954 args[0] = (int32_t)2;
1955 result.remove();
1956 assertEquals("offset-decimals format(1)", "2.0 meters",
1957 m2.format(args, 1, result, ignore, errorCode), TRUE);
1958
1959 args[0] = (double)2.5;
1960 result.remove();
1961 assertEquals("offset-decimals format(1)", "2.5 meters",
1962 m2.format(args, 1, result, ignore, errorCode), TRUE);
1963 errorCode.reset();
1964 }
1965
1966 #endif /* #if !UCONFIG_NO_FORMATTING */