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