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)
33static const char E_ACCENTED[]={E_WITH_ACUTE,0};
34
35void
36TestMessageFormat::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
67void 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
150void 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
167void 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
204IntlTest&
205operator<<( 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
246void 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
358void 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
380void 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. */
413void 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
448void 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
486void 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
528void 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
620void 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
641MessageFormat* 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
654void 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
826void 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
856void 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
885void 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
914void 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
926void 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
945void 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
1026void 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
1085void 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
1161void 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*.
1363static 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
1400void TestMessageFormat::testCopyConstructor2() {
1401    _testCopyConstructor2();
1402}
1403
1404/**
1405 * Verify that MessageFormat accomodates more than 10 arguments and
1406 * more than 10 subformats.
1407 */
1408void 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
1459void 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
1522void 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
1559void 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