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