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