• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  * Copyright (c) 1997-2007, International Business Machines
3  * Corporation and others. All Rights Reserved.
4  ********************************************************************
5  * File TMSGFMT.CPP
6  *
7  * Modification History:
8  *
9  *   Date        Name        Description
10  *   03/24/97    helena      Converted from Java.
11  *   07/11/97    helena      Updated to work on AIX.
12  *   08/04/97    jfitz       Updated to intltest
13  *******************************************************************/
14 
15 #include "unicode/utypes.h"
16 
17 #if !UCONFIG_NO_FORMATTING
18 
19 #include "tmsgfmt.h"
20 
21 #include "unicode/format.h"
22 #include "unicode/decimfmt.h"
23 #include "unicode/locid.h"
24 #include "unicode/msgfmt.h"
25 #include "unicode/numfmt.h"
26 #include "unicode/choicfmt.h"
27 #include "unicode/gregocal.h"
28 #include <stdio.h>
29 
30 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)31 TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
32                                   const char* &name, char* /*par*/) {
33     switch (index) {
34         TESTCASE(0,testBug1);
35         TESTCASE(1,testBug2);
36         TESTCASE(2,sample);
37         TESTCASE(3,PatternTest);
38         TESTCASE(4,testStaticFormat);
39         TESTCASE(5,testSimpleFormat);
40         TESTCASE(6,testMsgFormatChoice);
41         TESTCASE(7,testCopyConstructor);
42         TESTCASE(8,testAssignment);
43         TESTCASE(9,testClone);
44         TESTCASE(10,testEquals);
45         TESTCASE(11,testNotEquals);
46         TESTCASE(12,testSetLocale);
47         TESTCASE(13,testFormat);
48         TESTCASE(14,testParse);
49         TESTCASE(15,testAdopt);
50         TESTCASE(16,testCopyConstructor2);
51         TESTCASE(17,TestUnlimitedArgsAndSubformats);
52         TESTCASE(18,TestRBNF);
53         TESTCASE(19,TestTurkishCasing);
54         TESTCASE(20,testAutoQuoteApostrophe);
55         default: name = ""; break;
56     }
57 }
58 
testBug3()59 void TestMessageFormat::testBug3()
60 {
61     double myNumber = -123456;
62     DecimalFormat *form = 0;
63     Locale locale[] = {
64         Locale("ar", "", ""),
65         Locale("be", "", ""),
66         Locale("bg", "", ""),
67         Locale("ca", "", ""),
68         Locale("cs", "", ""),
69         Locale("da", "", ""),
70         Locale("de", "", ""),
71         Locale("de", "AT", ""),
72         Locale("de", "CH", ""),
73         Locale("el", "", ""),       // 10
74         Locale("en", "CA", ""),
75         Locale("en", "GB", ""),
76         Locale("en", "IE", ""),
77         Locale("en", "US", ""),
78         Locale("es", "", ""),
79         Locale("et", "", ""),
80         Locale("fi", "", ""),
81         Locale("fr", "", ""),
82         Locale("fr", "BE", ""),
83         Locale("fr", "CA", ""),     // 20
84         Locale("fr", "CH", ""),
85         Locale("he", "", ""),
86         Locale("hr", "", ""),
87         Locale("hu", "", ""),
88         Locale("is", "", ""),
89         Locale("it", "", ""),
90         Locale("it", "CH", ""),
91         Locale("ja", "", ""),
92         Locale("ko", "", ""),
93         Locale("lt", "", ""),       // 30
94         Locale("lv", "", ""),
95         Locale("mk", "", ""),
96         Locale("nl", "", ""),
97         Locale("nl", "BE", ""),
98         Locale("no", "", ""),
99         Locale("pl", "", ""),
100         Locale("pt", "", ""),
101         Locale("ro", "", ""),
102         Locale("ru", "", ""),
103         Locale("sh", "", ""),       // 40
104         Locale("sk", "", ""),
105         Locale("sl", "", ""),
106         Locale("sq", "", ""),
107         Locale("sr", "", ""),
108         Locale("sv", "", ""),
109         Locale("tr", "", ""),
110         Locale("uk", "", ""),
111         Locale("zh", "", ""),
112         Locale("zh", "TW", "")      // 49
113     };
114     int32_t i;
115     for (i= 0; i < 49; i++) {
116         UnicodeString buffer;
117         logln(locale[i].getDisplayName(buffer));
118         UErrorCode success = U_ZERO_ERROR;
119 //        form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
120         form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success);
121         if (U_FAILURE(success)) {
122             errln("Err: Number Format ");
123             logln("Number format creation failed.");
124             continue;
125         }
126         Formattable result;
127         FieldPosition pos(0);
128         buffer.remove();
129         form->format(myNumber, buffer, pos);
130         success = U_ZERO_ERROR;
131         ParsePosition parsePos;
132         form->parse(buffer, result, parsePos);
133         logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]"));
134         if (U_FAILURE(success)) {
135             errln("Err: Number Format parse");
136             logln("Number format parse failed.");
137         }
138         delete form;
139     }
140 }
141 
testBug1()142 void TestMessageFormat::testBug1()
143 {
144     const double limit[] = {0.0, 1.0, 2.0};
145     const UnicodeString formats[] = {"0.0<=Arg<1.0",
146                                "1.0<=Arg<2.0",
147                                "2.0<-Arg"};
148     ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3);
149     FieldPosition status(0);
150     UnicodeString toAppendTo;
151     cf->format((int32_t)1, toAppendTo, status);
152     if (toAppendTo != "1.0<=Arg<2.0") {
153         errln("ChoiceFormat cmp in testBug1");
154     }
155     logln(toAppendTo);
156     delete cf;
157 }
158 
testBug2()159 void TestMessageFormat::testBug2()
160 {
161     UErrorCode status = U_ZERO_ERROR;
162     UnicodeString result;
163     // {sfb} use double format in pattern, so result will match (not strictly necessary)
164     const UnicodeString pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}. ";
165     logln("The input pattern : " + pattern);
166     MessageFormat *fmt = new MessageFormat(pattern, status);
167     if (U_FAILURE(status)) {
168         errln("MessageFormat pattern creation failed.");
169         return;
170     }
171     logln("The output pattern is : " + fmt->toPattern(result));
172     if (pattern != result) {
173         errln("MessageFormat::toPattern() failed.");
174     }
175     delete fmt;
176 }
177 
178 #if 0
179 #if defined(_DEBUG) && U_IOSTREAM_SOURCE!=0
180 //----------------------------------------------------
181 // console I/O
182 //----------------------------------------------------
183 
184 #if U_IOSTREAM_SOURCE >= 199711
185 #   include <iostream>
186     std::ostream& operator<<(std::ostream& stream,  const Formattable&   obj);
187 #elif U_IOSTREAM_SOURCE >= 198506
188 #   include <iostream.h>
189     ostream& operator<<(ostream& stream,  const Formattable&   obj);
190 #endif
191 
192 #include "unicode/datefmt.h"
193 #include <stdlib.h>
194 #include <string.h>
195 
196 IntlTest&
197 operator<<( IntlTest&           stream,
198             const Formattable&  obj)
199 {
200     static DateFormat *defDateFormat = 0;
201 
202     UnicodeString buffer;
203     switch(obj.getType()) {
204         case Formattable::kDate :
205             if (defDateFormat == 0) {
206                 defDateFormat = DateFormat::createInstance();
207             }
208             defDateFormat->format(obj.getDate(), buffer);
209             stream << buffer;
210             break;
211         case Formattable::kDouble :
212             char convert[20];
213             sprintf( convert, "%lf", obj.getDouble() );
214             stream << convert << "D";
215             break;
216         case Formattable::kLong :
217             stream << obj.getLong() << "L";
218             break;
219         case Formattable::kString:
220             stream << "\"" << obj.getString(buffer) << "\"";
221             break;
222         case Formattable::kArray:
223             int32_t i, count;
224             const Formattable* array;
225             array = obj.getArray(count);
226             stream << "[";
227             for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
228             stream << "]";
229             break;
230         default:
231             stream << "INVALID_Formattable";
232     }
233     return stream;
234 }
235 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE!=0 */
236 #endif
237 
PatternTest()238 void TestMessageFormat::PatternTest()
239 {
240     Formattable testArgs[] = {
241         Formattable(double(1)), Formattable(double(3456)),
242             Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
243     };
244     UnicodeString testCases[] = {
245        "Quotes '', '{', 'a' {0} '{0}'",
246        "Quotes '', '{', 'a' {0,number} '{0}'",
247        "'{'1,number,'#',##} {1,number,'#',##}",
248        "There are {1} files on {2} at {3}.",
249        "On {2}, there are {1} files, with {0,number,currency}.",
250        "'{1,number,percent}', {1,number,percent},",
251        "'{1,date,full}', {1,date,full},",
252        "'{3,date,full}', {3,date,full},",
253        "'{1,number,#,##}' {1,number,#,##}",
254     };
255 
256     UnicodeString testResultPatterns[] = {
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     UnicodeString testResultStrings[] = {
269         "Quotes ', {, a 1 {0}",
270         "Quotes ', {, a 1 {0}",
271         "{1,number,#,##} #34,56",
272         "There are 3,456 files on Disk at 1/12/70 5:46 AM.",
273         "On Disk, there are 3,456 files, with $1.00.",
274         "{1,number,percent}, 345,600%,",
275         "{1,date,full}, Wednesday, December 31, 1969,",
276         "{3,date,full}, Monday, January 12, 1970,",
277         "{1,number,#,##} 34,56"
278     };
279 
280 
281     for (int32_t i = 0; i < 9; ++i) {
282         //it_out << "\nPat in:  " << testCases[i]);
283 
284         MessageFormat *form = 0;
285         UErrorCode success = U_ZERO_ERROR;
286         UnicodeString buffer;
287         form = new MessageFormat(testCases[i], Locale::getUS(), success);
288         if (U_FAILURE(success)) {
289             errln("MessageFormat creation failed.#1");
290             logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n");
291             continue;
292         }
293         if (form->toPattern(buffer) != testResultPatterns[i]) {
294             errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i);
295             //form->toPattern(buffer);
296             errln(((UnicodeString)" Orig: ") + testCases[i]);
297             errln(((UnicodeString)" Exp:  ") + testResultPatterns[i]);
298             errln(((UnicodeString)" Got:  ") + buffer);
299         }
300 
301         //it_out << "Pat out: " << form->toPattern(buffer));
302         UnicodeString result;
303         int32_t count = 4;
304         FieldPosition fieldpos(0);
305         form->format(testArgs, count, result, fieldpos, success);
306         if (U_FAILURE(success)) {
307             errln("MessageFormat failed test #3");
308             logln("TestMessageFormat::PatternTest failed test #3");
309             continue;
310         }
311         if (result != testResultStrings[i]) {
312             errln("TestMessageFormat::PatternTest failed test #4");
313             logln("TestMessageFormat::PatternTest failed #4.");
314             logln(UnicodeString("    Result: ") + result );
315             logln(UnicodeString("  Expected: ") + testResultStrings[i] );
316         }
317 
318 
319         //it_out << "Result:  " << result);
320 #if 0
321         /* TODO: Look at this test and see if this is still a valid test */
322         logln("---------------- test parse ----------------");
323 
324         form->toPattern(buffer);
325         logln("MSG pattern for parse: " + buffer);
326 
327         int32_t parseCount = 0;
328         Formattable* values = form->parse(result, parseCount, success);
329         if (U_FAILURE(success)) {
330             errln("MessageFormat failed test #5");
331             logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success);
332         } else if (parseCount != count) {
333             errln("MSG count not %d as expected. Got %d", count, parseCount);
334         }
335         UBool failed = FALSE;
336         for (int32_t j = 0; j < parseCount; ++j) {
337              if (values == 0 || testArgs[j] != values[j]) {
338                 errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
339                 errln(((UnicodeString)"MSG values[") + j + "]  : " + toString(values[j]));
340                 failed = TRUE;
341              }
342         }
343         if (failed)
344             errln("MessageFormat failed test #6");
345 #endif
346         delete form;
347     }
348 }
349 
sample()350 void TestMessageFormat::sample()
351 {
352     MessageFormat *form = 0;
353     UnicodeString buffer1, buffer2;
354     UErrorCode success = U_ZERO_ERROR;
355     form = new MessageFormat("There are {0} files on {1}", success);
356     if (U_FAILURE(success)) {
357         errln("Err: Message format creation failed");
358         logln("Sample message format creation failed.");
359         return;
360     }
361     UnicodeString abc("abc");
362     UnicodeString def("def");
363     Formattable testArgs1[] = { abc, def };
364     FieldPosition fieldpos(0);
365     assertEquals("format",
366                  "There are abc files on def",
367                  form->format(testArgs1, 2, buffer2, fieldpos, success));
368     assertSuccess("format", success);
369     delete form;
370 }
371 
testStaticFormat()372 void TestMessageFormat::testStaticFormat()
373 {
374     UErrorCode err = U_ZERO_ERROR;
375     Formattable arguments[] = {
376         (int32_t)7,
377         Formattable(UDate(8.71068e+011), Formattable::kIsDate),
378         "a disturbance in the Force"
379         };
380 
381     UnicodeString result;
382     result = MessageFormat::format(
383         "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
384         arguments,
385         3,
386         result,
387         err);
388 
389     if (U_FAILURE(err)) {
390         errln("TestMessageFormat::testStaticFormat #1");
391         logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err);
392         return;
393     }
394 
395     const UnicodeString expected(
396             "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
397     if (result != expected) {
398         errln("TestMessageFormat::testStaticFormat failed on test");
399         logln( UnicodeString("     Result: ") + result );
400         logln( UnicodeString("   Expected: ") + expected );
401     }
402 }
403 
404 /* When the default locale is tr, make sure that the pattern can still be parsed. */
TestTurkishCasing()405 void TestMessageFormat::TestTurkishCasing()
406 {
407     UErrorCode err = U_ZERO_ERROR;
408     Locale  saveDefaultLocale;
409     Locale::setDefault( Locale("tr"), err );
410 
411     Formattable arguments[] = {
412         (int32_t)7,
413         Formattable(UDate(8.71068e+011), Formattable::kIsDate),
414         "a disturbance in the Force"
415         };
416 
417     UnicodeString result;
418     result = MessageFormat::format(
419         "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
420         arguments,
421         3,
422         result,
423         err);
424 
425     if (U_FAILURE(err)) {
426         errln("TestTurkishCasing #1 with error code %s", u_errorName(err));
427         return;
428     }
429 
430     const UnicodeString expected(
431             "At 12:20:00 on 08.08.1997, there was a disturbance in the Force on planet 7.", "");
432     if (result != expected) {
433         errln("TestTurkishCasing failed on test");
434         errln( UnicodeString("     Result: ") + result );
435         errln( UnicodeString("   Expected: ") + expected );
436     }
437     Locale::setDefault( saveDefaultLocale, err );
438 }
439 
testSimpleFormat()440 void TestMessageFormat::testSimpleFormat(/* char* par */)
441 {
442     logln("running TestMessageFormat::testSimpleFormat");
443 
444     UErrorCode err = U_ZERO_ERROR;
445 
446     Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
447     Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
448     Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
449 
450     MessageFormat* form = new MessageFormat(
451         "The disk \"{1}\" contains {0} file(s).", err);
452 
453     UnicodeString string;
454     FieldPosition ignore(FieldPosition::DONT_CARE);
455     form->format(testArgs1, 2, string, ignore, err);
456     if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") {
457         errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1"));
458     }
459 
460     ignore.setField(FieldPosition::DONT_CARE);
461     string.remove();
462     form->format(testArgs2, 2, string, ignore, err);
463     if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
464         logln(string);
465         errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string);
466     }
467 
468     ignore.setField(FieldPosition::DONT_CARE);
469     string.remove();
470     form->format(testArgs3, 2, string, ignore, err);
471     if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") {
472         errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string);
473     }
474 
475     delete form;
476  }
477 
testMsgFormatChoice()478 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
479 {
480     logln("running TestMessageFormat::testMsgFormatChoice");
481 
482     UErrorCode err = U_ZERO_ERROR;
483 
484     MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err);
485     double filelimits[] = {0,1,2};
486     UnicodeString filepart[] = {"no files","one file","{0,number} files"};
487     ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
488     form->setFormat(1,*fileform); // NOT zero, see below
489         //is the format adopted?
490 
491     FieldPosition ignore(FieldPosition::DONT_CARE);
492     UnicodeString string;
493     Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
494     form->format(testArgs1, 2, string, ignore, err);
495     if (string != "The disk \"MyDisk\" contains no files.") {
496         errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
497     }
498 
499     ignore.setField(FieldPosition::DONT_CARE);
500     string.remove();
501     Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
502     form->format(testArgs2, 2, string, ignore, err);
503     if (string != "The disk \"MyDisk\" contains one file.") {
504         errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
505     }
506 
507     ignore.setField(FieldPosition::DONT_CARE);
508     string.remove();
509     Formattable testArgs3[] = {(int32_t)1273, "MyDisk"};
510     form->format(testArgs3, 2, string, ignore, err);
511     if (string != "The disk \"MyDisk\" contains 1,273 files.") {
512         errln("TestMessageFormat::testMsgFormatChoice failed on test #3");
513     }
514 
515     delete form;
516     delete fileform;
517 }
518 
519 
520 //---------------------------------
521 //  API Tests
522 //---------------------------------
523 
testCopyConstructor()524 void TestMessageFormat::testCopyConstructor()
525 {
526     UErrorCode success = U_ZERO_ERROR;
527     MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
528     MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
529     MessageFormat *y = 0;
530     y = new MessageFormat(*x);
531     if ( (*x == *y) &&
532          (*x != *z) &&
533          (*y != *z) )
534          logln("First test (operator ==): Passed!");
535     else {
536         errln("TestMessageFormat::testCopyConstructor failed #1");
537         logln("First test (operator ==): Failed!");
538     }
539     if ( ((*x == *y) && (*y == *x)) &&
540          ((*x != *z) && (*z != *x)) &&
541          ((*y != *z) && (*z != *y)) )
542         logln("Second test (equals): Passed!");
543     else {
544         errln("TestMessageFormat::testCopyConstructor failed #2");
545         logln("Second test (equals): Failed!");
546     }
547 
548     delete x;
549     delete y;
550     delete z;
551 }
552 
553 
testAssignment()554 void TestMessageFormat::testAssignment()
555 {
556     UErrorCode success = U_ZERO_ERROR;
557     MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
558     MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
559     MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success);
560     *y = *x;
561     if ( (*x == *y) &&
562          (*x != *z) &&
563          (*y != *z) )
564         logln("First test (operator ==): Passed!");
565     else {
566         errln( "TestMessageFormat::testAssignment failed #1");
567         logln("First test (operator ==): Failed!");
568     }
569     if ( ((*x == *y) && (*y == *x)) &&
570          ((*x != *z) && (*z != *x)) &&
571          ((*y != *z) && (*z != *y)) )
572         logln("Second test (equals): Passed!");
573     else {
574         errln("TestMessageFormat::testAssignment failed #2");
575         logln("Second test (equals): Failed!");
576     }
577 
578     delete x;
579     delete y;
580     delete z;
581 }
582 
testClone()583 void TestMessageFormat::testClone()
584 {
585     UErrorCode success = U_ZERO_ERROR;
586     MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
587     MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
588     MessageFormat *y = 0;
589     y = (MessageFormat*)x->clone();
590     if ( (*x == *y) &&
591          (*x != *z) &&
592          (*y != *z) )
593         logln("First test (operator ==): Passed!");
594     else {
595         errln("TestMessageFormat::testClone failed #1");
596         logln("First test (operator ==): Failed!");
597     }
598     if ( ((*x == *y) && (*y == *x)) &&
599          ((*x != *z) && (*z != *x)) &&
600          ((*y != *z) && (*z != *y)) )
601         logln("Second test (equals): Passed!");
602     else {
603         errln("TestMessageFormat::testClone failed #2");
604         logln("Second test (equals): Failed!");
605     }
606 
607     delete x;
608     delete y;
609     delete z;
610 }
611 
testEquals()612 void TestMessageFormat::testEquals()
613 {
614     UErrorCode success = U_ZERO_ERROR;
615     MessageFormat x("There are {0} files on {1}", success);
616     MessageFormat y("There are {0} files on {1}", success);
617     if (!(x == y)) {
618         errln( "TestMessageFormat::testEquals failed #1");
619         logln("First test (operator ==): Failed!");
620     }
621 
622 }
623 
testNotEquals()624 void TestMessageFormat::testNotEquals()
625 {
626     UErrorCode success = U_ZERO_ERROR;
627     MessageFormat x("There are {0} files on {1}", success);
628     MessageFormat y(x);
629     y.setLocale(Locale("fr"));
630     if (!(x != y)) {
631         errln( "TestMessageFormat::testEquals failed #1");
632         logln("First test (operator !=): Failed!");
633     }
634     y = x;
635     y.applyPattern("There are {0} files on {1} the disk", success);
636     if (!(x != y)) {
637         errln( "TestMessageFormat::testEquals failed #1");
638         logln("Second test (operator !=): Failed!");
639     }
640 }
641 
642 
testSetLocale()643 void TestMessageFormat::testSetLocale()
644 {
645     UErrorCode err = U_ZERO_ERROR;
646     GregorianCalendar cal(err);
647     Formattable arguments[] = {
648         456.83,
649         Formattable(UDate(8.71068e+011), Formattable::kIsDate),
650         "deposit"
651         };
652 
653     UnicodeString result;
654 
655     //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
656     UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
657     // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
658     // Just use unlocalized currency symbol.
659     //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
660     UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
661     compareStrEng += (UChar) 0x00a4;
662     compareStrEng += "456.83.";
663     // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
664     // Just use unlocalized currency symbol.
665     //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
666     UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
667     compareStrGer += "456,83 ";
668     compareStrGer += (UChar) 0x00a4;
669     compareStrGer += ".";
670 
671     MessageFormat msg( formatStr, err);
672     result = "";
673     FieldPosition pos(0);
674     result = msg.format(
675         arguments,
676         3,
677         result,
678         pos,
679         err);
680 
681     logln(result);
682     if (result != compareStrEng) {
683         errln("***  MSG format err.");
684     }
685 
686     msg.setLocale(Locale::getEnglish());
687     UBool getLocale_ok = TRUE;
688     if (msg.getLocale() != Locale::getEnglish()) {
689         errln("*** MSG getLocal err.");
690         getLocale_ok = FALSE;
691     }
692 
693     msg.setLocale(Locale::getGerman());
694 
695     if (msg.getLocale() != Locale::getGerman()) {
696         errln("*** MSG getLocal err.");
697         getLocale_ok = FALSE;
698     }
699 
700     msg.applyPattern( formatStr, err);
701 
702     pos.setField(0);
703     result = "";
704     result = msg.format(
705         arguments,
706         3,
707         result,
708         pos,
709         err);
710 
711     logln(result);
712     if (result == compareStrGer) {
713         logln("MSG setLocale tested.");
714     }else{
715         errln( "*** MSG setLocale err.");
716     }
717 
718     if (getLocale_ok) {
719         logln("MSG getLocale tested.");
720     }
721 }
722 
testFormat()723 void TestMessageFormat::testFormat()
724 {
725     UErrorCode err = U_ZERO_ERROR;
726     GregorianCalendar cal(err);
727 
728     const Formattable ftarray[] =
729     {
730         Formattable( UDate(8.71068e+011), Formattable::kIsDate )
731     };
732     const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable);
733     Formattable ft_arr( ftarray, ft_cnt );
734 
735     Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
736 
737     UnicodeString result;
738 
739     //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
740     UnicodeString formatStr = "On {0,date}, it began.";
741     UnicodeString compareStr = "On Aug 8, 1997, it began.";
742 
743     err = U_ZERO_ERROR;
744     MessageFormat msg( formatStr, err);
745     FieldPosition fp(0);
746 
747     result = "";
748     fp = 0;
749     result = msg.format(
750         *fmt,
751         result,
752         //FieldPosition(0),
753         fp,
754         err);
755 
756     if (err != U_ILLEGAL_ARGUMENT_ERROR) {
757         errln("*** MSG format without expected error code.");
758     }
759     err = U_ZERO_ERROR;
760 
761     result = "";
762     fp = 0;
763     result = msg.format(
764         ft_arr,
765         result,
766         //FieldPosition(0),
767         fp,
768         err);
769 
770     logln("MSG format( Formattable&, ... ) expected:" + compareStr);
771     logln("MSG format( Formattable&, ... )   result:" + result);
772     if (result != compareStr) {
773         errln("***  MSG format( Formattable&, .... ) err.");
774     }else{
775         logln("MSG format( Formattable&, ... ) tested.");
776     }
777 
778     delete fmt;
779 
780 }
781 
testParse()782 void TestMessageFormat::testParse()
783 {
784     UErrorCode err = U_ZERO_ERROR;
785     int32_t count;
786     UnicodeString msgFormatString = "{0} =sep= {1}";
787     MessageFormat msg( msgFormatString, err);
788     UnicodeString source = "abc =sep= def";
789     UnicodeString tmp1, tmp2;
790 
791     Formattable* fmt_arr = msg.parse( source, count, err );
792     if (U_FAILURE(err) || (!fmt_arr)) {
793         errln("*** MSG parse (ustring, count, err) error.");
794     }else{
795         logln("MSG parse -- count: %d", count);
796         if (count != 2) {
797             errln("*** MSG parse (ustring, count, err) count err.");
798         }else{
799             if ((fmt_arr[0].getType() == Formattable::kString)
800              && (fmt_arr[1].getType() == Formattable::kString)
801              && (fmt_arr[0].getString(tmp1) == "abc")
802              && (fmt_arr[1].getString(tmp2) == "def")) {
803                 logln("MSG parse (ustring, count, err) tested.");
804             }else{
805                 errln("*** MSG parse (ustring, count, err) result err.");
806             }
807         }
808     }
809     delete[] fmt_arr;
810 
811     ParsePosition pp(0);
812 
813     fmt_arr = msg.parse( source, pp, count );
814     if ((pp == 0) || (!fmt_arr)) {
815         errln("*** MSG parse (ustring, parsepos., count) error.");
816     }else{
817         logln("MSG parse -- count: %d", count);
818         if (count != 2) {
819             errln("*** MSG parse (ustring, parsepos., count) count err.");
820         }else{
821             if ((fmt_arr[0].getType() == Formattable::kString)
822              && (fmt_arr[1].getType() == Formattable::kString)
823              && (fmt_arr[0].getString(tmp1) == "abc")
824              && (fmt_arr[1].getString(tmp2) == "def")) {
825                 logln("MSG parse (ustring, parsepos., count) tested.");
826             }else{
827                 errln("*** MSG parse (ustring, parsepos., count) result err.");
828             }
829         }
830     }
831     delete[] fmt_arr;
832 
833     pp = 0;
834     Formattable fmta;
835 
836     msg.parseObject( source, fmta, pp );
837     if (pp == 0) {
838         errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
839     }else{
840         logln("MSG parse -- count: %d", count);
841         fmta.getArray(count);
842         if (count != 2) {
843             errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
844         }else{
845             if ((fmta[0].getType() == Formattable::kString)
846              && (fmta[1].getType() == Formattable::kString)
847              && (fmta[0].getString(tmp1) == "abc")
848              && (fmta[1].getString(tmp2) == "def")) {
849                 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
850             }else{
851                 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
852             }
853         }
854     }
855 }
856 
857 
testAdopt()858 void TestMessageFormat::testAdopt()
859 {
860     UErrorCode err = U_ZERO_ERROR;
861 
862     UnicodeString formatStr("{0,date},{1},{2,number}", "");
863     UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
864     err = U_ZERO_ERROR;
865     MessageFormat msg( formatStr, err);
866     MessageFormat msgCmp( formatStr, err);
867     int32_t count, countCmp;
868     const Format** formats = msg.getFormats(count);
869     const Format** formatsCmp = msgCmp.getFormats(countCmp);
870     const Format** formatsChg = 0;
871     const Format** formatsAct = 0;
872     int32_t countAct;
873     const Format* a;
874     const Format* b;
875     UnicodeString patCmp;
876     UnicodeString patAct;
877     Format** formatsToAdopt;
878 
879     if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
880         errln("Error getting Formats");
881         return;
882     }
883 
884     int32_t i;
885 
886     for (i = 0; i < count; i++) {
887         a = formats[i];
888         b = formatsCmp[i];
889         if ((a != NULL) && (b != NULL)) {
890             if (*a != *b) {
891                 errln("a != b");
892                 return;
893             }
894         }else if ((a != NULL) || (b != NULL)) {
895             errln("(a != NULL) || (b != NULL)");
896             return;
897         }
898     }
899 
900     msg.applyPattern( formatStrChange, err ); //set msg formats to something different
901     int32_t countChg;
902     formatsChg = msg.getFormats(countChg); // tested function
903     if (!formatsChg || (countChg != count)) {
904         errln("Error getting Formats");
905         return;
906     }
907 
908     UBool diff;
909     diff = TRUE;
910     for (i = 0; i < count; i++) {
911         a = formatsChg[i];
912         b = formatsCmp[i];
913         if ((a != NULL) && (b != NULL)) {
914             if (*a == *b) {
915                 logln("formatsChg == formatsCmp at index %d", i);
916                 diff = FALSE;
917             }
918         }
919     }
920     if (!diff) {
921         errln("*** MSG getFormats diff err.");
922         return;
923     }
924 
925     logln("MSG getFormats tested.");
926 
927     msg.setFormats( formatsCmp, countCmp ); //tested function
928 
929     formatsAct = msg.getFormats(countAct);
930     if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
931         errln("Error getting Formats");
932         return;
933     }
934 
935     assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
936     assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
937 
938     for (i = 0; i < countAct; i++) {
939         a = formatsAct[i];
940         b = formatsCmp[i];
941         if ((a != NULL) && (b != NULL)) {
942             if (*a != *b) {
943                 logln("formatsAct != formatsCmp at index %d", i);
944                 errln("a != b");
945                 return;
946             }
947         }else if ((a != NULL) || (b != NULL)) {
948             errln("(a != NULL) || (b != NULL)");
949             return;
950         }
951     }
952     logln("MSG setFormats tested.");
953 
954     //----
955 
956     msg.applyPattern( formatStrChange, err ); //set msg formats to something different
957 
958     formatsToAdopt = new Format* [countCmp];
959     if (!formatsToAdopt) {
960         errln("memory allocation error");
961         return;
962     }
963 
964     for (i = 0; i < countCmp; i++) {
965         if (formatsCmp[i] == NULL) {
966             formatsToAdopt[i] = NULL;
967         }else{
968             formatsToAdopt[i] = formatsCmp[i]->clone();
969             if (!formatsToAdopt[i]) {
970                 errln("Can't clone format at index %d", i);
971                 return;
972             }
973         }
974     }
975     msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
976     delete[] formatsToAdopt;
977 
978     assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
979     assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
980 
981     formatsAct = msg.getFormats(countAct);
982     if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
983         errln("Error getting Formats");
984         return;
985     }
986 
987     for (i = 0; i < countAct; i++) {
988         a = formatsAct[i];
989         b = formatsCmp[i];
990         if ((a != NULL) && (b != NULL)) {
991             if (*a != *b) {
992                 errln("a != b");
993                 return;
994             }
995         }else if ((a != NULL) || (b != NULL)) {
996             errln("(a != NULL) || (b != NULL)");
997             return;
998         }
999     }
1000     logln("MSG adoptFormats tested.");
1001 
1002     //---- adoptFormat
1003 
1004     msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1005 
1006     formatsToAdopt = new Format* [countCmp];
1007     if (!formatsToAdopt) {
1008         errln("memory allocation error");
1009         return;
1010     }
1011 
1012     for (i = 0; i < countCmp; i++) {
1013         if (formatsCmp[i] == NULL) {
1014             formatsToAdopt[i] = NULL;
1015         }else{
1016             formatsToAdopt[i] = formatsCmp[i]->clone();
1017             if (!formatsToAdopt[i]) {
1018                 errln("Can't clone format at index %d", i);
1019                 return;
1020             }
1021         }
1022     }
1023 
1024     for ( i = 0; i < countCmp; i++ ) {
1025         msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
1026     }
1027     delete[] formatsToAdopt; // array itself not needed in this case;
1028 
1029     assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1030     assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1031 
1032     formatsAct = msg.getFormats(countAct);
1033     if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1034         errln("Error getting Formats");
1035         return;
1036     }
1037 
1038     for (i = 0; i < countAct; i++) {
1039         a = formatsAct[i];
1040         b = formatsCmp[i];
1041         if ((a != NULL) && (b != NULL)) {
1042             if (*a != *b) {
1043                 errln("a != b");
1044                 return;
1045             }
1046         }else if ((a != NULL) || (b != NULL)) {
1047             errln("(a != NULL) || (b != NULL)");
1048             return;
1049         }
1050     }
1051     logln("MSG adoptFormat tested.");
1052 }
1053 
1054 // This test is a regression test for a fixed bug in the copy constructor.
1055 // It is kept as a global function rather than as a method since the test depends on memory values.
1056 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1057 // which is probably why it didn't show up in the regular test for the copy constructor.)
1058 // For this reason, the test isn't changed even though it contains function calls whose results are
1059 // not tested and had no problems. Actually, the test failed by *crashing*.
_testCopyConstructor2()1060 static void _testCopyConstructor2()
1061 {
1062     UErrorCode status = U_ZERO_ERROR;
1063     UnicodeString formatStr("Hello World on {0,date,full}", "");
1064     UnicodeString resultStr(" ", "");
1065     UnicodeString result;
1066     FieldPosition fp(0);
1067     UDate d = Calendar::getNow();
1068     const Formattable fargs( d, Formattable::kIsDate );
1069 
1070     MessageFormat* fmt1 = new MessageFormat( formatStr, status );
1071     MessageFormat* fmt2 = new MessageFormat( *fmt1 );
1072     MessageFormat* fmt3;
1073     MessageFormat* fmt4;
1074 
1075     if (fmt1 == NULL) it_err("testCopyConstructor2: (fmt1 != NULL)");
1076 
1077     result = fmt1->format( &fargs, 1, resultStr, fp, status );
1078 
1079     if (fmt2 == NULL) it_err("testCopyConstructor2: (fmt2 != NULL)");
1080 
1081     fmt3 = (MessageFormat*) fmt1->clone();
1082     fmt4 = (MessageFormat*) fmt2->clone();
1083 
1084     if (fmt3 == NULL) it_err("testCopyConstructor2: (fmt3 != NULL)");
1085     if (fmt4 == NULL) it_err("testCopyConstructor2: (fmt4 != NULL)");
1086 
1087     result = fmt1->format( &fargs, 1, resultStr, fp, status );
1088     result = fmt2->format( &fargs, 1, resultStr, fp, status );
1089     result = fmt3->format( &fargs, 1, resultStr, fp, status );
1090     result = fmt4->format( &fargs, 1, resultStr, fp, status );
1091     delete fmt1;
1092     delete fmt2;
1093     delete fmt3;
1094     delete fmt4;
1095 }
1096 
testCopyConstructor2()1097 void TestMessageFormat::testCopyConstructor2() {
1098     _testCopyConstructor2();
1099 }
1100 
1101 /**
1102  * Verify that MessageFormat accomodates more than 10 arguments and
1103  * more than 10 subformats.
1104  */
TestUnlimitedArgsAndSubformats()1105 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1106     UErrorCode ec = U_ZERO_ERROR;
1107     const UnicodeString pattern =
1108         "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1109         "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1110         "there were {1,number} werjes "
1111         "(a {3,number,percent} increase over {2,number}) "
1112         "despite the {4}''s efforts "
1113         "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1114     MessageFormat msg(pattern, ec);
1115     if (U_FAILURE(ec)) {
1116         errln("FAIL: constructor failed");
1117         return;
1118     }
1119 
1120     const Formattable ARGS[] = {
1121         Formattable(UDate(1e13), Formattable::kIsDate),
1122         Formattable((int32_t)1303),
1123         Formattable((int32_t)1202),
1124         Formattable(1303.0/1202 - 1),
1125         Formattable("Glimmung"),
1126         Formattable("the printers"),
1127         Formattable("Nick"),
1128         Formattable("his father"),
1129         Formattable("his mother"),
1130         Formattable("the spiddles"),
1131         Formattable("of course"),
1132         Formattable("Horace"),
1133     };
1134     const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]);
1135     Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
1136 
1137     UnicodeString expected =
1138         "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1139         "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1140         "there were 1,303 werjes "
1141         "(a 8% increase over 1,202) "
1142         "despite the Glimmung's efforts "
1143         "and to delight of the printers, Nick, his father, "
1144         "his mother, the spiddles, and of course Horace.";
1145     UnicodeString result;
1146     msg.format(ARGS_OBJ, result, ec);
1147     if (result == expected) {
1148         logln(result);
1149     } else {
1150         errln((UnicodeString)"FAIL: Got " + result +
1151               ", expected " + expected);
1152     }
1153 }
1154 
1155 // test RBNF extensions to message format
TestRBNF(void)1156 void TestMessageFormat::TestRBNF(void) {
1157     // WARNING: this depends on the RBNF formats for en_US
1158     Locale locale("en", "US", "");
1159 
1160     UErrorCode ec = U_ZERO_ERROR;
1161 
1162     UnicodeString values[] = {
1163         // decimal values do not format completely for ordinal or duration, and
1164         // do not always parse, so do not include them
1165         "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1166     };
1167     int32_t values_count = sizeof(values)/sizeof(values[0]);
1168 
1169     UnicodeString formats[] = {
1170         "There are {0,spellout} files to search.",
1171         "There are {0,spellout,%simplified} files to search.",
1172         "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1173         "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
1174         "Searching this file will take {0,duration} to complete.",
1175         "Searching this file will take {0,duration,%with-words} to complete.",
1176     };
1177     int32_t formats_count = sizeof(formats)/sizeof(formats[0]);
1178 
1179     Formattable args[1];
1180 
1181     NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
1182     if (U_FAILURE(ec)) {
1183         dataerrln("Error calling NumberFormat::createInstance()");
1184         return;
1185     }
1186 
1187     for (int i = 0; i < formats_count; ++i) {
1188         MessageFormat* fmt = new MessageFormat(formats[i], locale, ec);
1189         logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'");
1190 
1191         for (int j = 0; j < values_count; ++j) {
1192             ec = U_ZERO_ERROR;
1193             numFmt->parse(values[j], args[0], ec);
1194             if (U_FAILURE(ec)) {
1195                 errln((UnicodeString)"Failed to parse test argument " + values[j]);
1196             } else {
1197                 FieldPosition fp(0);
1198                 UnicodeString result;
1199                 fmt->format(args, 1, result, fp, ec);
1200                 logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec));
1201 
1202                 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1203                     int32_t count = 0;
1204                     Formattable* parseResult = fmt->parse(result, count, ec);
1205                     if (count != 1) {
1206                         errln((UnicodeString)"parse returned " + count + " args");
1207                     } else if (parseResult[0] != args[0]) {
1208                         errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
1209                     }
1210                     delete []parseResult;
1211                 }
1212             }
1213         }
1214         delete fmt;
1215     }
1216     delete numFmt;
1217 }
1218 
testAutoQuoteApostrophe(void)1219 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1220     const char* patterns[] = { // pattern, expected pattern
1221         "'", "''",
1222         "''", "''",
1223         "'{", "'{'",
1224         "' {", "'' {",
1225         "'a", "''a",
1226         "'{'a", "'{'a",
1227         "'{a'", "'{a'",
1228         "'{}", "'{}'",
1229         "{'", "{'",
1230         "{'a", "{'a",
1231         "{'a{}'a}'a", "{'a{}'a}''a",
1232         "'}'", "'}'",
1233         "'} '{'}'", "'} '{'}''",
1234         "'} {{{''", "'} {{{'''",
1235     };
1236     int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
1237 
1238     for (int i = 0; i < pattern_count; i += 2) {
1239         UErrorCode status = U_ZERO_ERROR;
1240         UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
1241         UnicodeString target(patterns[i+1]);
1242         if (target != result) {
1243             const int BUF2_LEN = 64;
1244             char buf[256];
1245             char buf2[BUF2_LEN];
1246             int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
1247             if (len >= BUF2_LEN) {
1248                 buf2[BUF2_LEN-1] = 0;
1249             }
1250             sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1251             errln(buf);
1252         }
1253     }
1254 }
1255 
1256 #endif /* #if !UCONFIG_NO_FORMATTING */
1257