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