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