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