]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tmsgfmt.cpp
ICU-531.31.tar.gz
[apple/icu.git] / icuSources / test / intltest / tmsgfmt.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2013, 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
22 #include "unicode/format.h"
23 #include "unicode/decimfmt.h"
24 #include "unicode/localpointer.h"
25 #include "unicode/locid.h"
26 #include "unicode/msgfmt.h"
27 #include "unicode/numfmt.h"
28 #include "unicode/choicfmt.h"
29 #include "unicode/messagepattern.h"
30 #include "unicode/selfmt.h"
31 #include "unicode/gregocal.h"
32 #include <stdio.h>
33
34 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
35
36 void
37 TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
38 const char* &name, char* /*par*/) {
39 TESTCASE_AUTO_BEGIN;
40 TESTCASE_AUTO(testBug1);
41 TESTCASE_AUTO(testBug2);
42 TESTCASE_AUTO(sample);
43 TESTCASE_AUTO(PatternTest);
44 TESTCASE_AUTO(testStaticFormat);
45 TESTCASE_AUTO(testSimpleFormat);
46 TESTCASE_AUTO(testMsgFormatChoice);
47 TESTCASE_AUTO(testCopyConstructor);
48 TESTCASE_AUTO(testAssignment);
49 TESTCASE_AUTO(testClone);
50 TESTCASE_AUTO(testEquals);
51 TESTCASE_AUTO(testNotEquals);
52 TESTCASE_AUTO(testSetLocale);
53 TESTCASE_AUTO(testFormat);
54 TESTCASE_AUTO(testParse);
55 TESTCASE_AUTO(testAdopt);
56 TESTCASE_AUTO(testCopyConstructor2);
57 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats);
58 TESTCASE_AUTO(TestRBNF);
59 TESTCASE_AUTO(TestTurkishCasing);
60 TESTCASE_AUTO(testAutoQuoteApostrophe);
61 TESTCASE_AUTO(testMsgFormatPlural);
62 TESTCASE_AUTO(testMsgFormatSelect);
63 TESTCASE_AUTO(testApostropheInPluralAndSelect);
64 TESTCASE_AUTO(TestApostropheMode);
65 TESTCASE_AUTO(TestCompatibleApostrophe);
66 TESTCASE_AUTO(testCoverage);
67 TESTCASE_AUTO(testGetFormatNames);
68 TESTCASE_AUTO(TestTrimArgumentName);
69 TESTCASE_AUTO(TestSelectOrdinal);
70 TESTCASE_AUTO(TestDecimals);
71 TESTCASE_AUTO_END;
72 }
73
74 void TestMessageFormat::testBug3()
75 {
76 double myNumber = -123456;
77 DecimalFormat *form = 0;
78 Locale locale[] = {
79 Locale("ar", "", ""),
80 Locale("be", "", ""),
81 Locale("bg", "", ""),
82 Locale("ca", "", ""),
83 Locale("cs", "", ""),
84 Locale("da", "", ""),
85 Locale("de", "", ""),
86 Locale("de", "AT", ""),
87 Locale("de", "CH", ""),
88 Locale("el", "", ""), // 10
89 Locale("en", "CA", ""),
90 Locale("en", "GB", ""),
91 Locale("en", "IE", ""),
92 Locale("en", "US", ""),
93 Locale("es", "", ""),
94 Locale("et", "", ""),
95 Locale("fi", "", ""),
96 Locale("fr", "", ""),
97 Locale("fr", "BE", ""),
98 Locale("fr", "CA", ""), // 20
99 Locale("fr", "CH", ""),
100 Locale("he", "", ""),
101 Locale("hr", "", ""),
102 Locale("hu", "", ""),
103 Locale("is", "", ""),
104 Locale("it", "", ""),
105 Locale("it", "CH", ""),
106 Locale("ja", "", ""),
107 Locale("ko", "", ""),
108 Locale("lt", "", ""), // 30
109 Locale("lv", "", ""),
110 Locale("mk", "", ""),
111 Locale("nl", "", ""),
112 Locale("nl", "BE", ""),
113 Locale("no", "", ""),
114 Locale("pl", "", ""),
115 Locale("pt", "", ""),
116 Locale("ro", "", ""),
117 Locale("ru", "", ""),
118 Locale("sh", "", ""), // 40
119 Locale("sk", "", ""),
120 Locale("sl", "", ""),
121 Locale("sq", "", ""),
122 Locale("sr", "", ""),
123 Locale("sv", "", ""),
124 Locale("tr", "", ""),
125 Locale("uk", "", ""),
126 Locale("zh", "", ""),
127 Locale("zh", "TW", "") // 49
128 };
129 int32_t i;
130 for (i= 0; i < 49; i++) {
131 UnicodeString buffer;
132 logln(locale[i].getDisplayName(buffer));
133 UErrorCode success = U_ZERO_ERROR;
134 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
135 form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success);
136 if (U_FAILURE(success)) {
137 errln("Err: Number Format ");
138 logln("Number format creation failed.");
139 continue;
140 }
141 Formattable result;
142 FieldPosition pos(0);
143 buffer.remove();
144 form->format(myNumber, buffer, pos);
145 success = U_ZERO_ERROR;
146 ParsePosition parsePos;
147 form->parse(buffer, result, parsePos);
148 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]"));
149 if (U_FAILURE(success)) {
150 errln("Err: Number Format parse");
151 logln("Number format parse failed.");
152 }
153 delete form;
154 }
155 }
156
157 void TestMessageFormat::testBug1()
158 {
159 const double limit[] = {0.0, 1.0, 2.0};
160 const UnicodeString formats[] = {"0.0<=Arg<1.0",
161 "1.0<=Arg<2.0",
162 "2.0<-Arg"};
163 ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3);
164 FieldPosition status(0);
165 UnicodeString toAppendTo;
166 cf->format((int32_t)1, toAppendTo, status);
167 if (toAppendTo != "1.0<=Arg<2.0") {
168 errln("ChoiceFormat cmp in testBug1");
169 }
170 logln(toAppendTo);
171 delete cf;
172 }
173
174 void TestMessageFormat::testBug2()
175 {
176 UErrorCode status = U_ZERO_ERROR;
177 UnicodeString result;
178 // {sfb} use double format in pattern, so result will match (not strictly necessary)
179 const UnicodeString pattern = "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
180 logln("The input pattern : " + pattern);
181 MessageFormat *fmt = new MessageFormat(pattern, status);
182 if (U_FAILURE(status)) {
183 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status));
184 return;
185 }
186 logln("The output pattern is : " + fmt->toPattern(result));
187 if (pattern != result) {
188 errln("MessageFormat::toPattern() failed.");
189 }
190 delete fmt;
191 }
192
193 #if 0
194 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
195 //----------------------------------------------------
196 // console I/O
197 //----------------------------------------------------
198
199 #include <iostream>
200 std::ostream& operator<<(std::ostream& stream, const Formattable& obj);
201
202 #include "unicode/datefmt.h"
203 #include <stdlib.h>
204 #include <string.h>
205
206 IntlTest&
207 operator<<( IntlTest& stream,
208 const Formattable& obj)
209 {
210 static DateFormat *defDateFormat = 0;
211
212 UnicodeString buffer;
213 switch(obj.getType()) {
214 case Formattable::kDate :
215 if (defDateFormat == 0) {
216 defDateFormat = DateFormat::createInstance();
217 }
218 defDateFormat->format(obj.getDate(), buffer);
219 stream << buffer;
220 break;
221 case Formattable::kDouble :
222 char convert[20];
223 sprintf( convert, "%lf", obj.getDouble() );
224 stream << convert << "D";
225 break;
226 case Formattable::kLong :
227 stream << obj.getLong() << "L";
228 break;
229 case Formattable::kString:
230 stream << "\"" << obj.getString(buffer) << "\"";
231 break;
232 case Formattable::kArray:
233 int32_t i, count;
234 const Formattable* array;
235 array = obj.getArray(count);
236 stream << "[";
237 for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
238 stream << "]";
239 break;
240 default:
241 stream << "INVALID_Formattable";
242 }
243 return stream;
244 }
245 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
246 #endif
247
248 void TestMessageFormat::PatternTest()
249 {
250 Formattable testArgs[] = {
251 Formattable(double(1)), Formattable(double(3456)),
252 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
253 };
254 UnicodeString testCases[] = {
255 "Quotes '', '{', 'a' {0} '{0}'",
256 "Quotes '', '{', 'a' {0,number} '{0}'",
257 "'{'1,number,'#',##} {1,number,'#',##}",
258 "There are {1} files on {2} at {3}.",
259 "On {2}, there are {1} files, with {0,number,currency}.",
260 "'{1,number,percent}', {1,number,percent},",
261 "'{1,date,full}', {1,date,full},",
262 "'{3,date,full}', {3,date,full},",
263 "'{1,number,#,##}' {1,number,#,##}",
264 };
265
266 // ICU 4.8 returns the original pattern (testCases),
267 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
268 /*UnicodeString testResultPatterns[] = {
269 "Quotes '', '{', a {0} '{'0}",
270 "Quotes '', '{', a {0,number} '{'0}",
271 "'{'1,number,#,##} {1,number,'#'#,##}",
272 "There are {1} files on {2} at {3}.",
273 "On {2}, there are {1} files, with {0,number,currency}.",
274 "'{'1,number,percent}, {1,number,percent},",
275 "'{'1,date,full}, {1,date,full},",
276 "'{'3,date,full}, {3,date,full},",
277 "'{'1,number,#,##} {1,number,#,##}"
278 };*/
279
280 UnicodeString testResultStrings[] = {
281 "Quotes ', {, 'a' 1 {0}",
282 "Quotes ', {, 'a' 1 {0}",
283 "{1,number,'#',##} #34,56",
284 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.",
285 "On Disk, there are 3,456 files, with $1.00.",
286 "{1,number,percent}, 345,600%,",
287 "{1,date,full}, Wednesday, December 31, 1969,",
288 "{3,date,full}, Monday, January 12, 1970,",
289 "{1,number,#,##} 34,56"
290 };
291
292
293 for (int32_t i = 0; i < 9; ++i) {
294 //it_out << "\nPat in: " << testCases[i]);
295
296 MessageFormat *form = 0;
297 UErrorCode success = U_ZERO_ERROR;
298 UnicodeString buffer;
299 form = new MessageFormat(testCases[i], Locale::getUS(), success);
300 if (U_FAILURE(success)) {
301 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success));
302 logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n");
303 continue;
304 }
305 // ICU 4.8 returns the original pattern (testCases),
306 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
307 if (form->toPattern(buffer) != testCases[i]) {
308 // Note: An alternative test would be to build MessagePattern objects for
309 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
310 // into account.
311 // (Too much trouble...)
312 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i);
313 //form->toPattern(buffer);
314 errln(((UnicodeString)" Orig: ") + testCases[i]);
315 errln(((UnicodeString)" Exp: ") + testCases[i]);
316 errln(((UnicodeString)" Got: ") + buffer);
317 }
318
319 //it_out << "Pat out: " << form->toPattern(buffer));
320 UnicodeString result;
321 int32_t count = 4;
322 FieldPosition fieldpos(0);
323 form->format(testArgs, count, result, fieldpos, success);
324 if (U_FAILURE(success)) {
325 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success));
326 logln("TestMessageFormat::PatternTest failed test #3");
327 continue;
328 }
329 if (result != testResultStrings[i]) {
330 errln("TestMessageFormat::PatternTest failed test #4");
331 logln("TestMessageFormat::PatternTest failed #4.");
332 logln(UnicodeString(" Result: ") + result );
333 logln(UnicodeString(" Expected: ") + testResultStrings[i] );
334 }
335
336
337 //it_out << "Result: " << result);
338 #if 0
339 /* TODO: Look at this test and see if this is still a valid test */
340 logln("---------------- test parse ----------------");
341
342 form->toPattern(buffer);
343 logln("MSG pattern for parse: " + buffer);
344
345 int32_t parseCount = 0;
346 Formattable* values = form->parse(result, parseCount, success);
347 if (U_FAILURE(success)) {
348 errln("MessageFormat failed test #5");
349 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success);
350 } else if (parseCount != count) {
351 errln("MSG count not %d as expected. Got %d", count, parseCount);
352 }
353 UBool failed = FALSE;
354 for (int32_t j = 0; j < parseCount; ++j) {
355 if (values == 0 || testArgs[j] != values[j]) {
356 errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
357 errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j]));
358 failed = TRUE;
359 }
360 }
361 if (failed)
362 errln("MessageFormat failed test #6");
363 #endif
364 delete form;
365 }
366 }
367
368 void TestMessageFormat::sample()
369 {
370 MessageFormat *form = 0;
371 UnicodeString buffer1, buffer2;
372 UErrorCode success = U_ZERO_ERROR;
373 form = new MessageFormat("There are {0} files on {1}", success);
374 if (U_FAILURE(success)) {
375 errln("Err: Message format creation failed");
376 logln("Sample message format creation failed.");
377 return;
378 }
379 UnicodeString abc("abc");
380 UnicodeString def("def");
381 Formattable testArgs1[] = { abc, def };
382 FieldPosition fieldpos(0);
383 assertEquals("format",
384 "There are abc files on def",
385 form->format(testArgs1, 2, buffer2, fieldpos, success));
386 assertSuccess("format", success);
387 delete form;
388 }
389
390 void TestMessageFormat::testStaticFormat()
391 {
392 UErrorCode err = U_ZERO_ERROR;
393 Formattable arguments[] = {
394 (int32_t)7,
395 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
396 "a disturbance in the Force"
397 };
398
399 UnicodeString result;
400 result = MessageFormat::format(
401 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
402 arguments,
403 3,
404 result,
405 err);
406
407 if (U_FAILURE(err)) {
408 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err));
409 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err);
410 return;
411 }
412
413 const UnicodeString expected(
414 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
415 if (result != expected) {
416 errln("TestMessageFormat::testStaticFormat failed on test");
417 logln( UnicodeString(" Result: ") + result );
418 logln( UnicodeString(" Expected: ") + expected );
419 }
420 }
421
422 /* When the default locale is tr, make sure that the pattern can still be parsed. */
423 void TestMessageFormat::TestTurkishCasing()
424 {
425 UErrorCode err = U_ZERO_ERROR;
426 Locale saveDefaultLocale;
427 Locale::setDefault( Locale("tr"), err );
428
429 Formattable arguments[] = {
430 (int32_t)7,
431 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
432 "a disturbance in the Force"
433 };
434
435 UnicodeString result;
436 result = MessageFormat::format(
437 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
438 arguments,
439 3,
440 result,
441 err);
442
443 if (U_FAILURE(err)) {
444 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err));
445 return;
446 }
447
448 const UnicodeString expected(
449 "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", "");
450 if (result != expected) {
451 errln("TestTurkishCasing failed on test");
452 errln( UnicodeString(" Result: ") + result );
453 errln( UnicodeString(" Expected: ") + expected );
454 }
455 Locale::setDefault( saveDefaultLocale, err );
456 }
457
458 void TestMessageFormat::testSimpleFormat(/* char* par */)
459 {
460 logln("running TestMessageFormat::testSimpleFormat");
461
462 UErrorCode err = U_ZERO_ERROR;
463
464 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
465 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
466 Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
467
468 MessageFormat* form = new MessageFormat(
469 "The disk \"{1}\" contains {0} file(s).", err);
470
471 UnicodeString string;
472 FieldPosition ignore(FieldPosition::DONT_CARE);
473 form->format(testArgs1, 2, string, ignore, err);
474 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") {
475 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err));
476 }
477
478 ignore.setField(FieldPosition::DONT_CARE);
479 string.remove();
480 form->format(testArgs2, 2, string, ignore, err);
481 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
482 logln(string);
483 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string + " - " + u_errorName(err));
484 }
485
486 ignore.setField(FieldPosition::DONT_CARE);
487 string.remove();
488 form->format(testArgs3, 2, string, ignore, err);
489 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") {
490 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string + " - " + u_errorName(err));
491 }
492
493 delete form;
494 }
495
496 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
497 {
498 logln("running TestMessageFormat::testMsgFormatChoice");
499
500 UErrorCode err = U_ZERO_ERROR;
501
502 MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err);
503 double filelimits[] = {0,1,2};
504 UnicodeString filepart[] = {"no files","one file","{0,number} files"};
505 ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
506 form->setFormat(1,*fileform); // NOT zero, see below
507 //is the format adopted?
508
509 FieldPosition ignore(FieldPosition::DONT_CARE);
510 UnicodeString string;
511 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
512 form->format(testArgs1, 2, string, ignore, err);
513 if (string != "The disk \"MyDisk\" contains no files.") {
514 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
515 }
516
517 ignore.setField(FieldPosition::DONT_CARE);
518 string.remove();
519 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
520 form->format(testArgs2, 2, string, ignore, err);
521 if (string != "The disk \"MyDisk\" contains one file.") {
522 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
523 }
524
525 ignore.setField(FieldPosition::DONT_CARE);
526 string.remove();
527 Formattable testArgs3[] = {(int32_t)1273, "MyDisk"};
528 form->format(testArgs3, 2, string, ignore, err);
529 if (string != "The disk \"MyDisk\" contains 1,273 files.") {
530 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err));
531 }
532
533 delete form;
534 delete fileform;
535 }
536
537
538 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
539 {
540 logln("running TestMessageFormat::testMsgFormatPlural");
541
542 UErrorCode err = U_ZERO_ERROR;
543 UnicodeString t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
544 UnicodeString t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
545 UnicodeString t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory.");
546 UnicodeString t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory.");
547 UnicodeString t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.");
548 MessageFormat* mfNum = new MessageFormat(t1, Locale("fr"), err);
549 if (U_FAILURE(err)) {
550 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err));
551 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err);
552 return;
553 }
554 Formattable testArgs1((int32_t)0);
555 FieldPosition ignore(FieldPosition::DONT_CARE);
556 UnicodeString numResult1;
557 mfNum->format(&testArgs1, 1, numResult1, ignore, err);
558
559 MessageFormat* mfAlpha = new MessageFormat(t2, Locale("fr"), err);
560 UnicodeString argName[] = {UnicodeString("argument")};
561 UnicodeString argNameResult;
562 mfAlpha->format(argName, &testArgs1, 1, argNameResult, err);
563 if (U_FAILURE(err)) {
564 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err));
565 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err);
566 delete mfNum;
567 return;
568 }
569 if ( numResult1 != argNameResult){
570 errln("TestMessageFormat::testMsgFormatPlural #1");
571 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
572 }
573 if ( numResult1 != UnicodeString("C\'est 0 fichier dans la liste.")) {
574 errln("TestMessageFormat::testMsgFormatPlural #1");
575 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
576 }
577 err = U_ZERO_ERROR;
578
579 delete mfNum;
580 delete mfAlpha;
581
582 MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err);
583 numResult1.remove();
584 Formattable testArgs2((int32_t)4);
585 mfNum2->format(&testArgs2, 1, numResult1, ignore, err);
586 MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err);
587 argNameResult.remove();
588 mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err);
589
590 if (U_FAILURE(err)) {
591 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
592 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err);
593 delete mfNum2;
594 return;
595 }
596 if ( numResult1 != argNameResult){
597 errln("TestMessageFormat::testMsgFormatPlural #2");
598 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
599 }
600 if ( numResult1 != UnicodeString("There are 4,0 zavoda in the directory.")) {
601 errln("TestMessageFormat::testMsgFormatPlural #2");
602 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
603 }
604
605 delete mfNum2;
606 delete mfAlpha2;
607
608 // nested formats
609 err = U_ZERO_ERROR;
610 MessageFormat* msgFmt = new MessageFormat(t5, Locale("fr"), err);
611 if (U_FAILURE(err)) {
612 errln("TestMessageFormat::test nested PluralFormat with argumentName");
613 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err);
614 delete msgFmt;
615 return;
616 }
617 Formattable testArgs3((int32_t)0);
618 argNameResult.remove();
619 msgFmt->format(&testArgs3, 1, argNameResult, ignore, err);
620 if (U_FAILURE(err)) {
621 errln("TestMessageFormat::test nested PluralFormat with argumentName");
622 }
623 if ( argNameResult!= UnicodeString("C'est 0,0 fichier dans la liste.")) {
624 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult);
625 logln(UnicodeString("The unexpected nested named PluralFormat."));
626 }
627 delete msgFmt;
628 }
629
630 void TestMessageFormat::testApostropheInPluralAndSelect() {
631 UErrorCode errorCode = U_ZERO_ERROR;
632 MessageFormat msgFmt(UNICODE_STRING_SIMPLE(
633 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"),
634 Locale::getEnglish(),
635 errorCode);
636 if (U_FAILURE(errorCode)) {
637 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode));
638 return;
639 }
640 UnicodeString expected = UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
641 Formattable args[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
642 internalFormat(
643 &msgFmt, args, 2, expected,
644 "MessageFormat with apostrophes in plural/select arguments failed:\n");
645 }
646
647 void TestMessageFormat::internalFormat(MessageFormat* msgFmt ,
648 Formattable* args , int32_t numOfArgs ,
649 UnicodeString expected, const char* errMsg)
650 {
651 UnicodeString result;
652 FieldPosition ignore(FieldPosition::DONT_CARE);
653 UErrorCode status = U_ZERO_ERROR;
654
655 //Format with passed arguments
656 msgFmt->format( args , numOfArgs , result, ignore, status);
657 if (U_FAILURE(status)) {
658 dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) );
659 }
660 //Compare expected with obtained result
661 if ( result!= expected ) {
662 UnicodeString err = UnicodeString(errMsg);
663 err+= UnicodeString(":Unexpected Result \n Expected: " + expected + "\n Obtained: " + result + "\n");
664 dataerrln(err);
665 }
666 }
667
668 MessageFormat* TestMessageFormat::internalCreate(
669 UnicodeString pattern ,Locale locale ,UErrorCode &status , char* errMsg)
670 {
671 //Create the MessageFormat with simple SelectFormat
672 MessageFormat* msgFmt = new MessageFormat(pattern, locale, status);
673 if (U_FAILURE(status)) {
674 dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) );
675 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status);
676 return NULL;
677 }
678 return msgFmt;
679 }
680
681 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
682 {
683 logln("running TestMessageFormat::testMsgFormatSelect");
684
685 UErrorCode err = U_ZERO_ERROR;
686 //French Pattern
687 UnicodeString t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
688
689 err = U_ZERO_ERROR;
690 //Create the MessageFormat with simple French pattern
691 MessageFormat* msgFmt1 = internalCreate(t1.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t1");
692 if (!U_FAILURE(err)) {
693 //Arguments
694 Formattable testArgs10[] = {"Kirti","female"};
695 Formattable testArgs11[] = {"Victor","other"};
696 Formattable testArgs12[] = {"Ash","unknown"};
697 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
698 UnicodeString exp[] = {
699 "Kirti est all\\u00E9e \\u00E0 Paris." ,
700 "Victor est all\\u00E9 \\u00E0 Paris.",
701 "Ash est all\\u00E9 \\u00E0 Paris."};
702 //Format
703 for( int i=0; i< 3; i++){
704 internalFormat( msgFmt1 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
705 }
706 }
707 delete msgFmt1;
708
709 //Quoted French Pattern
710 UnicodeString t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
711 err = U_ZERO_ERROR;
712 //Create the MessageFormat with Quoted French pattern
713 MessageFormat* msgFmt2 = internalCreate(t2.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t2");
714 if (!U_FAILURE(err)) {
715 //Arguments
716 Formattable testArgs10[] = {"Kirti","female"};
717 Formattable testArgs11[] = {"Victor","other"};
718 Formattable testArgs12[] = {"Ash","male"};
719 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
720 UnicodeString exp[] = {
721 "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
722 "Victor est all\\u00E9 c'est \\u00E0 Paris.",
723 "Ash est all\\u00E9 c'est \\u00E0 Paris."};
724 //Format
725 for( int i=0; i< 3; i++){
726 internalFormat( msgFmt2 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
727 }
728 }
729 delete msgFmt2;
730
731 //English Pattern
732 UnicodeString t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
733 err = U_ZERO_ERROR;
734 //Create the MessageFormat with English pattern
735 MessageFormat* msgFmt3 = internalCreate(t3, Locale("en"),err,(char*)"From TestMessageFormat::TestSelectFormat create t3");
736 if (!U_FAILURE(err)) {
737 //Arguments
738 Formattable testArgs10[] = {"female"};
739 Formattable testArgs11[] = {"other"};
740 Formattable testArgs12[] = {"male"};
741 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
742 UnicodeString exp[] = {
743 "FEMALE FR company published new books." ,
744 "FR otherValue published new books.",
745 "MALE FR company published new books."};
746 //Format
747 for( int i=0; i< 3; i++){
748 internalFormat( msgFmt3 , testArgs[i], 1, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
749 }
750 }
751 delete msgFmt3;
752
753 //Nested patterns with plural, number ,choice ,select format etc.
754 //Select Format with embedded number format
755 UnicodeString t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
756 err = U_ZERO_ERROR;
757 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
758 MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4");
759 if (!U_FAILURE(err)) {
760 //Arguments
761 Formattable testArgs10[] = {"Kirti","female",(int32_t)6};
762 Formattable testArgs11[] = {"Kirti","female",100.100};
763 Formattable testArgs12[] = {"Kirti","other",(int32_t)6};
764 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
765 UnicodeString exp[] = {
766 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
767 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
768 "Kirti est all\\u00E9 \\u00E0 Paris."};
769 //Format
770 for( int i=0; i< 3; i++){
771 internalFormat( msgFmt4 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
772 }
773 }
774 delete msgFmt4;
775
776 //Plural format with embedded select format
777 UnicodeString t5("{0} {1, plural, one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}} other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}} \\u00E0 Paris.");
778 err = U_ZERO_ERROR;
779 //Create the MessageFormat with Plural format with embedded select format(nested pattern)
780 MessageFormat* msgFmt5 = internalCreate(t5.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t5");
781 if (!U_FAILURE(err)) {
782 //Arguments
783 Formattable testArgs10[] = {"Kirti",(int32_t)6,"female"};
784 Formattable testArgs11[] = {"Kirti",(int32_t)1,"female"};
785 Formattable testArgs12[] = {"Ash",(int32_t)1,"other"};
786 Formattable testArgs13[] = {"Ash",(int32_t)5,"other"};
787 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13};
788 UnicodeString exp[] = {
789 "Kirti sont all\\u00E9es \\u00E0 Paris." ,
790 "Kirti est all\\u00E9e \\u00E0 Paris.",
791 "Ash est all\\u00E9 \\u00E0 Paris.",
792 "Ash sont all\\u00E9s \\u00E0 Paris."};
793 //Format
794 for( int i=0; i< 4; i++){
795 internalFormat( msgFmt5 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
796 }
797 }
798 delete msgFmt5;
799
800 err = U_ZERO_ERROR;
801 //Select, plural, and number formats heavily nested
802 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.");
803 //Create the MessageFormat with Select, plural, and number formats heavily nested
804 MessageFormat* msgFmt6 = internalCreate(t6, Locale("de"),err,(char*)"From TestMessageFormat::TestSelectFormat create t6");
805 if (!U_FAILURE(err)) {
806 //Arguments
807 Formattable testArgs10[] = {"Kirti","other",(int32_t)1,"other"};
808 Formattable testArgs11[] = {"Kirti","other",(int32_t)6,"other"};
809 Formattable testArgs12[] = {"Kirti","other",(int32_t)1,"female"};
810 Formattable testArgs13[] = {"Kirti","other",(int32_t)3,"female"};
811 Formattable testArgs14[] = {"Kirti","female",(int32_t)1,"female"};
812 Formattable testArgs15[] = {"Kirti","female",(int32_t)5,"female"};
813 Formattable testArgs16[] = {"Kirti","female",(int32_t)1,"other"};
814 Formattable testArgs17[] = {"Kirti","female",(int32_t)5,"other"};
815 Formattable testArgs18[] = {"Kirti","mixed",(int32_t)1,"mixed"};
816 Formattable testArgs19[] = {"Kirti","mixed",(int32_t)1,"other"};
817 Formattable testArgs20[] = {"Kirti","female",(int32_t)1,"mixed"};
818 Formattable testArgs21[] = {"Kirti","mixed",(int32_t)5,"mixed"};
819 Formattable testArgs22[] = {"Kirti","mixed",(int32_t)5,"other"};
820 Formattable testArgs23[] = {"Kirti","female",(int32_t)5,"mixed"};
821 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13,
822 testArgs14,testArgs15,testArgs16,testArgs17,
823 testArgs18,testArgs19,testArgs20,testArgs21,
824 testArgs22,testArgs23 };
825 UnicodeString exp[] = {
826 "Kirti und sein Freund gingen nach Paris." ,
827 "Kirti und seine 6 Freunde gingen nach Paris." ,
828 "Kirti und seine Freundin gingen nach Paris.",
829 "Kirti und seine 3 Freundinnen gingen nach Paris.",
830 "Kirti und ihre Freundin gingen nach Paris.",
831 "Kirti und ihre 5 Freundinnen gingen nach Paris.",
832 "Kirti und ihr Freund gingen nach Paris.",
833 "Kirti und ihre 5 Freunde gingen nach Paris.",
834 "Kirti und sein Freund gingen nach Paris.",
835 "Kirti und sein Freund gingen nach Paris.",
836 "Kirti und ihr Freund gingen nach Paris.",
837 "Kirti und seine 5 Freunde gingen nach Paris." ,
838 "Kirti und seine 5 Freunde gingen nach Paris." ,
839 "Kirti und ihre 5 Freunde gingen nach Paris."
840 };
841 //Format
842 for( int i=0; i< 14; i++){
843 internalFormat( msgFmt6 , testArgs[i], 4, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
844 }
845 }
846 delete msgFmt6;
847 }
848
849 //---------------------------------
850 // API Tests
851 //---------------------------------
852
853 void TestMessageFormat::testCopyConstructor()
854 {
855 UErrorCode success = U_ZERO_ERROR;
856 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
857 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
858 MessageFormat *y = 0;
859 y = new MessageFormat(*x);
860 if ( (*x == *y) &&
861 (*x != *z) &&
862 (*y != *z) )
863 logln("First test (operator ==): Passed!");
864 else {
865 errln("TestMessageFormat::testCopyConstructor failed #1");
866 logln("First test (operator ==): Failed!");
867 }
868 if ( ((*x == *y) && (*y == *x)) &&
869 ((*x != *z) && (*z != *x)) &&
870 ((*y != *z) && (*z != *y)) )
871 logln("Second test (equals): Passed!");
872 else {
873 errln("TestMessageFormat::testCopyConstructor failed #2");
874 logln("Second test (equals): Failed!");
875 }
876
877 delete x;
878 delete y;
879 delete z;
880 }
881
882
883 void TestMessageFormat::testAssignment()
884 {
885 UErrorCode success = U_ZERO_ERROR;
886 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
887 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
888 MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success);
889 *y = *x;
890 if ( (*x == *y) &&
891 (*x != *z) &&
892 (*y != *z) )
893 logln("First test (operator ==): Passed!");
894 else {
895 errln( "TestMessageFormat::testAssignment failed #1");
896 logln("First test (operator ==): Failed!");
897 }
898 if ( ((*x == *y) && (*y == *x)) &&
899 ((*x != *z) && (*z != *x)) &&
900 ((*y != *z) && (*z != *y)) )
901 logln("Second test (equals): Passed!");
902 else {
903 errln("TestMessageFormat::testAssignment failed #2");
904 logln("Second test (equals): Failed!");
905 }
906
907 delete x;
908 delete y;
909 delete z;
910 }
911
912 void TestMessageFormat::testClone()
913 {
914 UErrorCode success = U_ZERO_ERROR;
915 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
916 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
917 MessageFormat *y = 0;
918 y = (MessageFormat*)x->clone();
919 if ( (*x == *y) &&
920 (*x != *z) &&
921 (*y != *z) )
922 logln("First test (operator ==): Passed!");
923 else {
924 errln("TestMessageFormat::testClone failed #1");
925 logln("First test (operator ==): Failed!");
926 }
927 if ( ((*x == *y) && (*y == *x)) &&
928 ((*x != *z) && (*z != *x)) &&
929 ((*y != *z) && (*z != *y)) )
930 logln("Second test (equals): Passed!");
931 else {
932 errln("TestMessageFormat::testClone failed #2");
933 logln("Second test (equals): Failed!");
934 }
935
936 delete x;
937 delete y;
938 delete z;
939 }
940
941 void TestMessageFormat::testEquals()
942 {
943 UErrorCode success = U_ZERO_ERROR;
944 MessageFormat x("There are {0} files on {1}", success);
945 MessageFormat y("There are {0} files on {1}", success);
946 if (!(x == y)) {
947 errln( "TestMessageFormat::testEquals failed #1");
948 logln("First test (operator ==): Failed!");
949 }
950
951 }
952
953 void TestMessageFormat::testNotEquals()
954 {
955 UErrorCode success = U_ZERO_ERROR;
956 MessageFormat x("There are {0} files on {1}", success);
957 MessageFormat y(x);
958 y.setLocale(Locale("fr"));
959 if (!(x != y)) {
960 errln( "TestMessageFormat::testEquals failed #1");
961 logln("First test (operator !=): Failed!");
962 }
963 y = x;
964 y.applyPattern("There are {0} files on {1} the disk", success);
965 if (!(x != y)) {
966 errln( "TestMessageFormat::testEquals failed #1");
967 logln("Second test (operator !=): Failed!");
968 }
969 }
970
971
972 void TestMessageFormat::testSetLocale()
973 {
974 UErrorCode err = U_ZERO_ERROR;
975 GregorianCalendar cal(err);
976 Formattable arguments[] = {
977 456.83,
978 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
979 "deposit"
980 };
981
982 UnicodeString result;
983
984 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
985 UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
986 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
987 // Just use unlocalized currency symbol.
988 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
989 UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
990 compareStrEng += (UChar) 0x00a4;
991 compareStrEng += "456.83.";
992 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
993 // Just use unlocalized currency symbol.
994 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
995 UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
996 compareStrGer += "456,83";
997 compareStrGer += (UChar) 0x00a0;
998 compareStrGer += (UChar) 0x00a4;
999 compareStrGer += ".";
1000
1001 MessageFormat msg( formatStr, err);
1002 result = "";
1003 FieldPosition pos(0);
1004 result = msg.format(
1005 arguments,
1006 3,
1007 result,
1008 pos,
1009 err);
1010
1011 logln(result);
1012 if (result != compareStrEng) {
1013 dataerrln("*** MSG format err. - %s", u_errorName(err));
1014 }
1015
1016 msg.setLocale(Locale::getEnglish());
1017 UBool getLocale_ok = TRUE;
1018 if (msg.getLocale() != Locale::getEnglish()) {
1019 errln("*** MSG getLocal err.");
1020 getLocale_ok = FALSE;
1021 }
1022
1023 msg.setLocale(Locale::getGerman());
1024
1025 if (msg.getLocale() != Locale::getGerman()) {
1026 errln("*** MSG getLocal err.");
1027 getLocale_ok = FALSE;
1028 }
1029
1030 msg.applyPattern( formatStr, err);
1031
1032 pos.setField(0);
1033 result = "";
1034 result = msg.format(
1035 arguments,
1036 3,
1037 result,
1038 pos,
1039 err);
1040
1041 logln(result);
1042 if (result == compareStrGer) {
1043 logln("MSG setLocale tested.");
1044 }else{
1045 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err));
1046 }
1047
1048 if (getLocale_ok) {
1049 logln("MSG getLocale tested.");
1050 }
1051 }
1052
1053 void TestMessageFormat::testFormat()
1054 {
1055 UErrorCode err = U_ZERO_ERROR;
1056 GregorianCalendar cal(err);
1057
1058 const Formattable ftarray[] =
1059 {
1060 Formattable( UDate(8.71068e+011), Formattable::kIsDate )
1061 };
1062 const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable);
1063 Formattable ft_arr( ftarray, ft_cnt );
1064
1065 Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
1066
1067 UnicodeString result;
1068
1069 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
1070 UnicodeString formatStr = "On {0,date}, it began.";
1071 UnicodeString compareStr = "On Aug 8, 1997, it began.";
1072
1073 err = U_ZERO_ERROR;
1074 MessageFormat msg( formatStr, err);
1075 FieldPosition fp(0);
1076
1077 result = "";
1078 fp = 0;
1079 result = msg.format(
1080 *fmt,
1081 result,
1082 //FieldPosition(0),
1083 fp,
1084 err);
1085
1086 if (err != U_ILLEGAL_ARGUMENT_ERROR) {
1087 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err));
1088 }
1089 err = U_ZERO_ERROR;
1090
1091 result = "";
1092 fp = 0;
1093 result = msg.format(
1094 ft_arr,
1095 result,
1096 //FieldPosition(0),
1097 fp,
1098 err);
1099
1100 logln("MSG format( Formattable&, ... ) expected:" + compareStr);
1101 logln("MSG format( Formattable&, ... ) result:" + result);
1102 if (result != compareStr) {
1103 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err));
1104 }else{
1105 logln("MSG format( Formattable&, ... ) tested.");
1106 }
1107
1108 delete fmt;
1109
1110 }
1111
1112 void TestMessageFormat::testParse()
1113 {
1114 UErrorCode err = U_ZERO_ERROR;
1115 int32_t count;
1116 UnicodeString msgFormatString = "{0} =sep= {1}";
1117 MessageFormat msg( msgFormatString, err);
1118 UnicodeString source = "abc =sep= def";
1119 UnicodeString tmp1, tmp2;
1120
1121 Formattable* fmt_arr = msg.parse( source, count, err );
1122 if (U_FAILURE(err) || (!fmt_arr)) {
1123 errln("*** MSG parse (ustring, count, err) error.");
1124 }else{
1125 logln("MSG parse -- count: %d", count);
1126 if (count != 2) {
1127 errln("*** MSG parse (ustring, count, err) count err.");
1128 }else{
1129 if ((fmt_arr[0].getType() == Formattable::kString)
1130 && (fmt_arr[1].getType() == Formattable::kString)
1131 && (fmt_arr[0].getString(tmp1) == "abc")
1132 && (fmt_arr[1].getString(tmp2) == "def")) {
1133 logln("MSG parse (ustring, count, err) tested.");
1134 }else{
1135 errln("*** MSG parse (ustring, count, err) result err.");
1136 }
1137 }
1138 }
1139 delete[] fmt_arr;
1140
1141 ParsePosition pp(0);
1142
1143 fmt_arr = msg.parse( source, pp, count );
1144 if ((pp == 0) || (!fmt_arr)) {
1145 errln("*** MSG parse (ustring, parsepos., count) error.");
1146 }else{
1147 logln("MSG parse -- count: %d", count);
1148 if (count != 2) {
1149 errln("*** MSG parse (ustring, parsepos., count) count err.");
1150 }else{
1151 if ((fmt_arr[0].getType() == Formattable::kString)
1152 && (fmt_arr[1].getType() == Formattable::kString)
1153 && (fmt_arr[0].getString(tmp1) == "abc")
1154 && (fmt_arr[1].getString(tmp2) == "def")) {
1155 logln("MSG parse (ustring, parsepos., count) tested.");
1156 }else{
1157 errln("*** MSG parse (ustring, parsepos., count) result err.");
1158 }
1159 }
1160 }
1161 delete[] fmt_arr;
1162
1163 pp = 0;
1164 Formattable fmta;
1165
1166 msg.parseObject( source, fmta, pp );
1167 if (pp == 0) {
1168 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1169 }else{
1170 logln("MSG parse -- count: %d", count);
1171 fmta.getArray(count);
1172 if (count != 2) {
1173 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1174 }else{
1175 if ((fmta[0].getType() == Formattable::kString)
1176 && (fmta[1].getType() == Formattable::kString)
1177 && (fmta[0].getString(tmp1) == "abc")
1178 && (fmta[1].getString(tmp2) == "def")) {
1179 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
1180 }else{
1181 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1182 }
1183 }
1184 }
1185 }
1186
1187
1188 void TestMessageFormat::testAdopt()
1189 {
1190 UErrorCode err = U_ZERO_ERROR;
1191
1192 UnicodeString formatStr("{0,date},{1},{2,number}", "");
1193 UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
1194 err = U_ZERO_ERROR;
1195 MessageFormat msg( formatStr, err);
1196 MessageFormat msgCmp( formatStr, err);
1197 if (U_FAILURE(err)) {
1198 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err));
1199 return;
1200 }
1201 int32_t count, countCmp;
1202 const Format** formats = msg.getFormats(count);
1203 const Format** formatsCmp = msgCmp.getFormats(countCmp);
1204 const Format** formatsChg = 0;
1205 const Format** formatsAct = 0;
1206 int32_t countAct;
1207 const Format* a;
1208 const Format* b;
1209 UnicodeString patCmp;
1210 UnicodeString patAct;
1211 Format** formatsToAdopt;
1212
1213 if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
1214 dataerrln("Error getting Formats");
1215 return;
1216 }
1217
1218 int32_t i;
1219
1220 for (i = 0; i < count; i++) {
1221 a = formats[i];
1222 b = formatsCmp[i];
1223 if ((a != NULL) && (b != NULL)) {
1224 if (*a != *b) {
1225 errln("a != b");
1226 return;
1227 }
1228 }else if ((a != NULL) || (b != NULL)) {
1229 errln("(a != NULL) || (b != NULL)");
1230 return;
1231 }
1232 }
1233
1234 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1235 int32_t countChg;
1236 formatsChg = msg.getFormats(countChg); // tested function
1237 if (!formatsChg || (countChg != count)) {
1238 errln("Error getting Formats");
1239 return;
1240 }
1241
1242 UBool diff;
1243 diff = TRUE;
1244 for (i = 0; i < count; i++) {
1245 a = formatsChg[i];
1246 b = formatsCmp[i];
1247 if ((a != NULL) && (b != NULL)) {
1248 if (*a == *b) {
1249 logln("formatsChg == formatsCmp at index %d", i);
1250 diff = FALSE;
1251 }
1252 }
1253 }
1254 if (!diff) {
1255 errln("*** MSG getFormats diff err.");
1256 return;
1257 }
1258
1259 logln("MSG getFormats tested.");
1260
1261 msg.setFormats( formatsCmp, countCmp ); //tested function
1262
1263 formatsAct = msg.getFormats(countAct);
1264 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1265 errln("Error getting Formats");
1266 return;
1267 }
1268
1269 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1270 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1271 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1272 msg.toPattern(patCmp.remove());
1273 if (!patCmp.isBogus()) {
1274 errln("msg.setFormat().toPattern() succeeds.");
1275 }
1276
1277 for (i = 0; i < countAct; i++) {
1278 a = formatsAct[i];
1279 b = formatsCmp[i];
1280 if ((a != NULL) && (b != NULL)) {
1281 if (*a != *b) {
1282 logln("formatsAct != formatsCmp at index %d", i);
1283 errln("a != b");
1284 return;
1285 }
1286 }else if ((a != NULL) || (b != NULL)) {
1287 errln("(a != NULL) || (b != NULL)");
1288 return;
1289 }
1290 }
1291 logln("MSG setFormats tested.");
1292
1293 //----
1294
1295 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1296
1297 formatsToAdopt = new Format* [countCmp];
1298 if (!formatsToAdopt) {
1299 errln("memory allocation error");
1300 return;
1301 }
1302
1303 for (i = 0; i < countCmp; i++) {
1304 if (formatsCmp[i] == NULL) {
1305 formatsToAdopt[i] = NULL;
1306 }else{
1307 formatsToAdopt[i] = formatsCmp[i]->clone();
1308 if (!formatsToAdopt[i]) {
1309 errln("Can't clone format at index %d", i);
1310 return;
1311 }
1312 }
1313 }
1314 msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
1315 delete[] formatsToAdopt;
1316
1317 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1318 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1319 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1320
1321 formatsAct = msg.getFormats(countAct);
1322 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1323 errln("Error getting Formats");
1324 return;
1325 }
1326
1327 for (i = 0; i < countAct; i++) {
1328 a = formatsAct[i];
1329 b = formatsCmp[i];
1330 if ((a != NULL) && (b != NULL)) {
1331 if (*a != *b) {
1332 errln("a != b");
1333 return;
1334 }
1335 }else if ((a != NULL) || (b != NULL)) {
1336 errln("(a != NULL) || (b != NULL)");
1337 return;
1338 }
1339 }
1340 logln("MSG adoptFormats tested.");
1341
1342 //---- adoptFormat
1343
1344 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1345
1346 formatsToAdopt = new Format* [countCmp];
1347 if (!formatsToAdopt) {
1348 errln("memory allocation error");
1349 return;
1350 }
1351
1352 for (i = 0; i < countCmp; i++) {
1353 if (formatsCmp[i] == NULL) {
1354 formatsToAdopt[i] = NULL;
1355 }else{
1356 formatsToAdopt[i] = formatsCmp[i]->clone();
1357 if (!formatsToAdopt[i]) {
1358 errln("Can't clone format at index %d", i);
1359 return;
1360 }
1361 }
1362 }
1363
1364 for ( i = 0; i < countCmp; i++ ) {
1365 msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
1366 }
1367 delete[] formatsToAdopt; // array itself not needed in this case;
1368
1369 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1370 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1371 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1372
1373 formatsAct = msg.getFormats(countAct);
1374 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1375 errln("Error getting Formats");
1376 return;
1377 }
1378
1379 for (i = 0; i < countAct; i++) {
1380 a = formatsAct[i];
1381 b = formatsCmp[i];
1382 if ((a != NULL) && (b != NULL)) {
1383 if (*a != *b) {
1384 errln("a != b");
1385 return;
1386 }
1387 }else if ((a != NULL) || (b != NULL)) {
1388 errln("(a != NULL) || (b != NULL)");
1389 return;
1390 }
1391 }
1392 logln("MSG adoptFormat tested.");
1393 }
1394
1395 // This test is a regression test for a fixed bug in the copy constructor.
1396 // It is kept as a global function rather than as a method since the test depends on memory values.
1397 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1398 // which is probably why it didn't show up in the regular test for the copy constructor.)
1399 // For this reason, the test isn't changed even though it contains function calls whose results are
1400 // not tested and had no problems. Actually, the test failed by *crashing*.
1401 static void _testCopyConstructor2()
1402 {
1403 UErrorCode status = U_ZERO_ERROR;
1404 UnicodeString formatStr("Hello World on {0,date,full}", "");
1405 UnicodeString resultStr(" ", "");
1406 UnicodeString result;
1407 FieldPosition fp(0);
1408 UDate d = Calendar::getNow();
1409 const Formattable fargs( d, Formattable::kIsDate );
1410
1411 MessageFormat* fmt1 = new MessageFormat( formatStr, status );
1412 MessageFormat* fmt2 = NULL;
1413 MessageFormat* fmt3 = NULL;
1414 MessageFormat* fmt4 = NULL;
1415
1416 if (fmt1 == NULL) {
1417 it_err("testCopyConstructor2: (fmt1 != NULL)");
1418 goto cleanup;
1419 }
1420
1421 fmt2 = new MessageFormat( *fmt1 );
1422 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1423
1424 if (fmt2 == NULL) {
1425 it_err("testCopyConstructor2: (fmt2 != NULL)");
1426 goto cleanup;
1427 }
1428
1429 fmt3 = (MessageFormat*) fmt1->clone();
1430 fmt4 = (MessageFormat*) fmt2->clone();
1431
1432 if (fmt3 == NULL) {
1433 it_err("testCopyConstructor2: (fmt3 != NULL)");
1434 goto cleanup;
1435 }
1436 if (fmt4 == NULL) {
1437 it_err("testCopyConstructor2: (fmt4 != NULL)");
1438 goto cleanup;
1439 }
1440
1441 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1442 result = fmt2->format( &fargs, 1, resultStr, fp, status );
1443 result = fmt3->format( &fargs, 1, resultStr, fp, status );
1444 result = fmt4->format( &fargs, 1, resultStr, fp, status );
1445
1446 cleanup:
1447 delete fmt1;
1448 delete fmt2;
1449 delete fmt3;
1450 delete fmt4;
1451 }
1452
1453 void TestMessageFormat::testCopyConstructor2() {
1454 _testCopyConstructor2();
1455 }
1456
1457 /**
1458 * Verify that MessageFormat accomodates more than 10 arguments and
1459 * more than 10 subformats.
1460 */
1461 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1462 UErrorCode ec = U_ZERO_ERROR;
1463 const UnicodeString pattern =
1464 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1465 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1466 "there were {1,number} werjes "
1467 "(a {3,number,percent} increase over {2,number}) "
1468 "despite the {4}''s efforts "
1469 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1470 MessageFormat msg(pattern, ec);
1471 if (U_FAILURE(ec)) {
1472 dataerrln("FAIL: constructor failed - %s", u_errorName(ec));
1473 return;
1474 }
1475
1476 const Formattable ARGS[] = {
1477 Formattable(UDate(1e13), Formattable::kIsDate),
1478 Formattable((int32_t)1303),
1479 Formattable((int32_t)1202),
1480 Formattable(1303.0/1202 - 1),
1481 Formattable("Glimmung"),
1482 Formattable("the printers"),
1483 Formattable("Nick"),
1484 Formattable("his father"),
1485 Formattable("his mother"),
1486 Formattable("the spiddles"),
1487 Formattable("of course"),
1488 Formattable("Horace"),
1489 };
1490 const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]);
1491 Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
1492
1493 UnicodeString expected =
1494 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1495 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1496 "there were 1,303 werjes "
1497 "(a 8% increase over 1,202) "
1498 "despite the Glimmung's efforts "
1499 "and to delight of the printers, Nick, his father, "
1500 "his mother, the spiddles, and of course Horace.";
1501 UnicodeString result;
1502 msg.format(ARGS_OBJ, result, ec);
1503 if (result == expected) {
1504 logln(result);
1505 } else {
1506 errln((UnicodeString)"FAIL: Got " + result +
1507 ", expected " + expected);
1508 }
1509 }
1510
1511 // test RBNF extensions to message format
1512 void TestMessageFormat::TestRBNF(void) {
1513 // WARNING: this depends on the RBNF formats for en_US
1514 Locale locale("en", "US", "");
1515
1516 UErrorCode ec = U_ZERO_ERROR;
1517
1518 UnicodeString values[] = {
1519 // decimal values do not format completely for ordinal or duration, and
1520 // do not always parse, so do not include them
1521 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1522 };
1523 int32_t values_count = sizeof(values)/sizeof(values[0]);
1524
1525 UnicodeString formats[] = {
1526 "There are {0,spellout} files to search.",
1527 "There are {0,spellout,%simplified} files to search.",
1528 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1529 "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
1530 "Searching this file will take {0,duration} to complete.",
1531 "Searching this file will take {0,duration,%with-words} to complete.",
1532 };
1533 int32_t formats_count = sizeof(formats)/sizeof(formats[0]);
1534
1535 Formattable args[1];
1536
1537 NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
1538 if (U_FAILURE(ec)) {
1539 dataerrln("Error calling NumberFormat::createInstance()");
1540 return;
1541 }
1542
1543 for (int i = 0; i < formats_count; ++i) {
1544 MessageFormat* fmt = new MessageFormat(formats[i], locale, ec);
1545 logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'");
1546
1547 for (int j = 0; j < values_count; ++j) {
1548 ec = U_ZERO_ERROR;
1549 numFmt->parse(values[j], args[0], ec);
1550 if (U_FAILURE(ec)) {
1551 errln((UnicodeString)"Failed to parse test argument " + values[j]);
1552 } else {
1553 FieldPosition fp(0);
1554 UnicodeString result;
1555 fmt->format(args, 1, result, fp, ec);
1556 logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec));
1557
1558 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1559 int32_t count = 0;
1560 Formattable* parseResult = fmt->parse(result, count, ec);
1561 if (count != 1) {
1562 errln((UnicodeString)"parse returned " + count + " args");
1563 } else if (parseResult[0] != args[0]) {
1564 errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
1565 }
1566 delete []parseResult;
1567 }
1568 }
1569 }
1570 delete fmt;
1571 }
1572 delete numFmt;
1573 }
1574
1575 UnicodeString TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern& pattern) {
1576 UnicodeString us(pattern.getPatternString());
1577 int count = pattern.countParts();
1578 for (int i = count; i > 0;) {
1579 const MessagePattern::Part& part = pattern.getPart(--i);
1580 if (part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1581 us.remove(part.getIndex(), part.getLimit() - part.getIndex());
1582 }
1583 }
1584 return us;
1585 }
1586
1587 void TestMessageFormat::TestApostropheMode() {
1588 UErrorCode status = U_ZERO_ERROR;
1589 MessagePattern *ado_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL, status);
1590 MessagePattern *adr_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED, status);
1591 if (ado_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1592 errln("wrong value from ado_mp->getApostropheMode().");
1593 }
1594 if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1595 errln("wrong value from adr_mp->getApostropheMode().");
1596 }
1597
1598
1599 UnicodeString tuples[] = {
1600 // Desired output
1601 // DOUBLE_OPTIONAL pattern
1602 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1603 "I see {many}", "I see '{many}'", "",
1604 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1605 "I dont know", "I dont know", "I don't know",
1606 "I don't know", "I don't know", "I don''t know",
1607 "I don't know", "I don''t know", "I don''t know"
1608 };
1609 int32_t tuples_count = LENGTHOF(tuples);
1610
1611 for (int i = 0; i < tuples_count; i += 3) {
1612 UnicodeString& desired = tuples[i];
1613 UnicodeString& ado_pattern = tuples[i + 1];
1614 UErrorCode status = U_ZERO_ERROR;
1615 assertEquals("DOUBLE_OPTIONAL failure",
1616 desired,
1617 GetPatternAndSkipSyntax(ado_mp->parse(ado_pattern, NULL, status)));
1618 UnicodeString& adr_pattern = tuples[i + 2].isEmpty() ? ado_pattern : tuples[i + 2];
1619 assertEquals("DOUBLE_REQUIRED failure", desired,
1620 GetPatternAndSkipSyntax(adr_mp->parse(adr_pattern, NULL, status)));
1621 }
1622 delete adr_mp;
1623 delete ado_mp;
1624 }
1625
1626
1627 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
1628 void TestMessageFormat::TestCompatibleApostrophe() {
1629 // Message with choice argument which does not contain another argument.
1630 // The JDK performs only one apostrophe-quoting pass on this pattern.
1631 UnicodeString pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
1632
1633 UErrorCode ec = U_ZERO_ERROR;
1634 MessageFormat compMsg("", Locale::getUS(), ec);
1635 compMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, ec);
1636 if (compMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1637 errln("wrong value from compMsg.getApostropheMode().");
1638 }
1639
1640 MessageFormat icuMsg("", Locale::getUS(), ec);
1641 icuMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_OPTIONAL, NULL, ec);
1642 if (icuMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1643 errln("wrong value from icuMsg.getApostropheMode().");
1644 }
1645
1646 Formattable zero0[] = { (int32_t)0 };
1647 FieldPosition fieldpos(0);
1648 UnicodeString buffer1, buffer2;
1649 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1650 "ab12'3'4''.yz",
1651 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1652 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1653 "ab1'2'3''4''.yz",
1654 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1655
1656 // Message with choice argument which contains a nested simple argument.
1657 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1658 buffer1.remove();
1659 buffer2.remove();
1660 pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1661 compMsg.applyPattern(pattern, ec);
1662 icuMsg.applyPattern(pattern, ec);
1663 if (U_FAILURE(ec)) {
1664 dataerrln("Unable to applyPattern - %s", u_errorName(ec));
1665 } else {
1666 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1667 "ab1234'.0xyz",
1668 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1669 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1670 "ab1'2'3''4''.#x0yz",
1671 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1672 }
1673
1674 // This part is copied over from Java tests but cannot be properly tested here
1675 // because we do not have a live reference implementation with JDK behavior.
1676 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1677 /*
1678 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1679 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1680 "12'3'4''.",
1681 choice.format(0));
1682 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1683 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1684 "12'3'4''.{0,number,#x}",
1685 choice.format(0));
1686 */
1687 }
1688
1689 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1690 const char* patterns[] = { // pattern, expected pattern
1691 "'", "''",
1692 "''", "''",
1693 "'{", "'{'",
1694 "' {", "'' {",
1695 "'a", "''a",
1696 "'{'a", "'{'a",
1697 "'{a'", "'{a'",
1698 "'{}", "'{}'",
1699 "{'", "{'",
1700 "{'a", "{'a",
1701 "{'a{}'a}'a", "{'a{}'a}''a",
1702 "'}'", "'}'",
1703 "'} '{'}'", "'} '{'}''",
1704 "'} {{{''", "'} {{{'''",
1705 };
1706 int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
1707
1708 for (int i = 0; i < pattern_count; i += 2) {
1709 UErrorCode status = U_ZERO_ERROR;
1710 UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
1711 UnicodeString target(patterns[i+1]);
1712 if (target != result) {
1713 const int BUF2_LEN = 64;
1714 char buf[256];
1715 char buf2[BUF2_LEN];
1716 int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
1717 if (len >= BUF2_LEN) {
1718 buf2[BUF2_LEN-1] = 0;
1719 }
1720 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1721 errln(buf);
1722 }
1723 }
1724 }
1725
1726 void TestMessageFormat::testCoverage(void) {
1727 UErrorCode status = U_ZERO_ERROR;
1728 UnicodeString testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1729 MessageFormat *msgfmt = new MessageFormat(testformat, Locale("fr"), status);
1730 if (msgfmt == NULL || U_FAILURE(status)) {
1731 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status));
1732 return;
1733 }
1734 if (!msgfmt->usesNamedArguments()) {
1735 errln("FAIL: Unable to detect usage of named arguments.");
1736 }
1737 const double limit[] = {0.0, 1.0, 2.0};
1738 const UnicodeString formats[] = {"0.0<=Arg<1.0",
1739 "1.0<=Arg<2.0",
1740 "2.0<-Arg"};
1741 ChoiceFormat cf(limit, formats, 3);
1742
1743 msgfmt->setFormat("set", cf, status);
1744
1745 StringEnumeration *en = msgfmt->getFormatNames(status);
1746 if (en == NULL || U_FAILURE(status)) {
1747 errln("FAIL: Unable to get format names enumeration.");
1748 } else {
1749 int32_t count = 0;
1750 en->reset(status);
1751 count = en->count(status);
1752 if (U_FAILURE(status)) {
1753 errln("FAIL: Unable to get format name enumeration count.");
1754 } else {
1755 for (int32_t i = 0; i < count; i++) {
1756 en->snext(status);
1757 if (U_FAILURE(status)) {
1758 errln("FAIL: Error enumerating through names.");
1759 break;
1760 }
1761 }
1762 }
1763 }
1764
1765 // adoptFormat() takes ownership of the input Format object.
1766 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1767 Format *cfClone = cf.clone();
1768 msgfmt->adoptFormat("adopt", cfClone, status);
1769
1770 delete en;
1771 delete msgfmt;
1772
1773 msgfmt = new MessageFormat("'", status);
1774 if (msgfmt == NULL || U_FAILURE(status)) {
1775 errln("FAIL: Unable to create MessageFormat.");
1776 return;
1777 }
1778 if (msgfmt->usesNamedArguments()) {
1779 errln("FAIL: Unable to detect usage of named arguments.");
1780 }
1781
1782 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1783 // on a MessageFormat without named arguments.
1784 msgfmt->setFormat("formatName", cf, status);
1785 if (U_FAILURE(status)) {
1786 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1787 }
1788 status = U_ZERO_ERROR;
1789 en = msgfmt->getFormatNames(status);
1790 if (U_FAILURE(status)) {
1791 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1792 }
1793
1794 delete en;
1795 delete msgfmt;
1796 }
1797
1798 void TestMessageFormat::testGetFormatNames() {
1799 IcuTestErrorCode errorCode(*this, "testGetFormatNames");
1800 MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode);
1801 if(errorCode.logDataIfFailureAndReset("MessageFormat() failed")) {
1802 return;
1803 }
1804 LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode));
1805 if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1806 return;
1807 }
1808 const UnicodeString *name;
1809 name = names->snext(errorCode);
1810 if (name == NULL || errorCode.isFailure()) {
1811 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName());
1812 errorCode.reset();
1813 return;
1814 }
1815 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) {
1816 return;
1817 }
1818 name = names->snext(errorCode);
1819 if (name == NULL || errorCode.isFailure()) {
1820 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName());
1821 errorCode.reset();
1822 return;
1823 }
1824 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) {
1825 return;
1826 }
1827 name = names->snext(errorCode);
1828 if (name == NULL || errorCode.isFailure()) {
1829 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName());
1830 errorCode.reset();
1831 return;
1832 }
1833 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) {
1834 return;
1835 }
1836 name = names->snext(errorCode);
1837 if (name != NULL) {
1838 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name);
1839 return;
1840 }
1841 }
1842
1843 void TestMessageFormat::TestTrimArgumentName() {
1844 // ICU 4.8 allows and ignores white space around argument names and numbers.
1845 IcuTestErrorCode errorCode(*this, "TestTrimArgumentName");
1846 MessageFormat m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode);
1847 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1848 return;
1849 }
1850 Formattable args[1] = { (int32_t)2 };
1851 FieldPosition ignore(0);
1852 UnicodeString result;
1853 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1854 m.format(args, 1, result, ignore, errorCode));
1855
1856 m.applyPattern("x { _oOo_ , number , integer } y", errorCode);
1857 UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_");
1858 args[0].setLong(3);
1859 result.remove();
1860 assertEquals("trim-named-arg format() failed", "x 3 y",
1861 m.format(&argName, args, 1, result, errorCode));
1862 }
1863
1864 void TestMessageFormat::TestSelectOrdinal() {
1865 IcuTestErrorCode errorCode(*this, "TestSelectOrdinal");
1866 // Test plural & ordinal together,
1867 // to make sure that we get the correct cached PluralSelector for each.
1868 MessageFormat m(
1869 "{0,plural,one{1 file}other{# files}}, "
1870 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
1871 Locale::getEnglish(), errorCode);
1872 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1873 return;
1874 }
1875 Formattable args[1] = { (int32_t)21 };
1876 FieldPosition ignore(0);
1877 UnicodeString result;
1878 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file",
1879 m.format(args, 1, result, ignore, errorCode), TRUE);
1880
1881 args[0].setLong(2);
1882 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1883 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1884
1885 args[0].setLong(1);
1886 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1887 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1888
1889 args[0].setLong(3);
1890 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1891 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1892
1893 errorCode.logDataIfFailureAndReset("");
1894 }
1895
1896 void TestMessageFormat::TestDecimals() {
1897 IcuTestErrorCode errorCode(*this, "TestDecimals");
1898 // Simple number replacement.
1899 MessageFormat m(
1900 "{0,plural,one{one meter}other{# meters}}",
1901 Locale::getEnglish(), errorCode);
1902 Formattable args[1] = { (int32_t)1 };
1903 FieldPosition ignore;
1904 UnicodeString result;
1905 assertEquals("simple format(1)", "one meter",
1906 m.format(args, 1, result, ignore, errorCode), TRUE);
1907
1908 args[0] = (double)1.5;
1909 result.remove();
1910 assertEquals("simple format(1.5)", "1.5 meters",
1911 m.format(args, 1, result, ignore, errorCode), TRUE);
1912
1913 // Simple but explicit.
1914 MessageFormat m0(
1915 "{0,plural,one{one meter}other{{0} meters}}",
1916 Locale::getEnglish(), errorCode);
1917 args[0] = (int32_t)1;
1918 result.remove();
1919 assertEquals("explicit format(1)", "one meter",
1920 m0.format(args, 1, result, ignore, errorCode), TRUE);
1921
1922 args[0] = (double)1.5;
1923 result.remove();
1924 assertEquals("explicit format(1.5)", "1.5 meters",
1925 m0.format(args, 1, result, ignore, errorCode), TRUE);
1926
1927 // With offset and specific simple format with optional decimals.
1928 MessageFormat m1(
1929 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1930 Locale::getEnglish(), errorCode);
1931 args[0] = (int32_t)1;
1932 result.remove();
1933 assertEquals("offset format(1)", "01 meters",
1934 m1.format(args, 1, result, ignore, errorCode), TRUE);
1935
1936 args[0] = (int32_t)2;
1937 result.remove();
1938 assertEquals("offset format(1)", "another meter",
1939 m1.format(args, 1, result, ignore, errorCode), TRUE);
1940
1941 args[0] = (double)2.5;
1942 result.remove();
1943 assertEquals("offset format(1)", "02.5 meters",
1944 m1.format(args, 1, result, ignore, errorCode), TRUE);
1945
1946 // With offset and specific simple format with forced decimals.
1947 MessageFormat m2(
1948 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1949 Locale::getEnglish(), errorCode);
1950 args[0] = (int32_t)1;
1951 result.remove();
1952 assertEquals("offset-decimals format(1)", "1.0 meters",
1953 m2.format(args, 1, result, ignore, errorCode), TRUE);
1954
1955 args[0] = (int32_t)2;
1956 result.remove();
1957 assertEquals("offset-decimals format(1)", "2.0 meters",
1958 m2.format(args, 1, result, ignore, errorCode), TRUE);
1959
1960 args[0] = (double)2.5;
1961 result.remove();
1962 assertEquals("offset-decimals format(1)", "2.5 meters",
1963 m2.format(args, 1, result, ignore, errorCode), TRUE);
1964 errorCode.reset();
1965 }
1966
1967 #endif /* #if !UCONFIG_NO_FORMATTING */